Files
wecom_it_smart_desk/docs/aTrust零信任系统集成分析.md

880 lines
34 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# aTrust零信任访问控制系统 — 集成分析
> 分析日期:2026-06-11 | 文档版本:V1.1 | 基于aTrust OpenAPI V3官方接口文档(docx版,适用于≥2.4.10版本)
---
## 1. 系统概述
### 1.1 产品定位
**深信服aTrust**是零信任访问控制系统(Zero Trust Network Access, ZTNA),替代传统VPN。员工远程办公时通过aTrust接入内网,系统基于身份认证+终端授信+最小权限原则进行访问控制。
> **关键事实**:总部员工必须安装联软安全助手,远程办公通过aTrust连入内网。这两个系统分别覆盖了内网和VPN两种接入场景的终端。
### 1.2 与IT服务台的关系
| 场景 | aTrust的角色 |
|------|-------------|
| 员工远程报修 | 坐席需要知道员工是否通过VPN在线、VPN IP地址 |
| 终端排查 | 查询VPN会话状态、接入方式、虚拟IP |
| 安全应急 | 紧急踢出可疑VPN会话、断开远程连接 |
| 终端映射 | 获取远程办公员工的终端信息(联软可能未覆盖的VPN终端) |
---
## 2. API概览
### 2.1 端点统计
| API模块 | 端点数 | 与IT服务台相关度 |
|---------|--------|-----------------|
| 在线监控 | 2 | 🔴 P0 |
| 用户管理 | 26 | 🟡 P1 |
| 组织架构管理 | 18 | ⚪ P2 |
| 角色管理 | 19 | ⚪ P2 |
| 应用管理 | 14 | ⚪ P2 |
| 应用分类管理 | 8 | ⚪ P2 |
| 认证服务器管理 | 2 | ⚪ P2 |
| 用户目录管理 | 5 | ⚪ P2 |
| **终端管理** | **9** | **🔴 P0** |
| 安全中心管理 | 1 | ⚪ P2 |
| **合计** | **104** | — |
### 2.2 认证机制
| 项目 | 说明 |
|------|------|
| **算法** | HMAC-SHA256 |
| **4个必填Header** | `x-ca-sign`(签名值)、`x-ca-key`API ID)、`x-ca-timestamp`10位秒级时间戳)、`x-ca-nonce`UUID v4随机数) |
| **签名密钥** | `appId={API_ID}&appSecret={API_SECRET}&timestamp={ts}&nonce={nonce}` |
| **签名串** | `{pathname}?{sorted_query}&{compact_json_body}` |
| **签名计算** | `HMAC-SHA256(signing_key, signing_string)` → 64位十六进制 |
| **防重放** | timestamp + nonce 组合 |
| **传输协议** | 必须HTTPS |
| **IP白名单** | 支持配置接入IP限制 |
| **默认端口** | 4433 |
| **频率限制** | **8 QPS**(所有接口共享8请求/秒) |
| **实体并发** | 同一实体的操作必须串行调用,否则可能数据覆盖 |
| **时间校验** | 请求时间戳与服务器时间差>5分钟则拒绝 |
| **Python Demo** | https://bbs.sangfor.com.cn/atrustdeveloper/openapiV3/openapi-demo_for_python.7z |
#### 签名计算示例
```python
import hmac, hashlib, uuid, time, json
API_ID = "8165305"
API_SECRET = "aebd2e3c5ea2449aa2928c102f9db276"
# Step 1: 构建签名串
pathname = "/api/v1/monitor/getUserStatus"
query = "pageIndex=1&pageSize=20" # key按ASCII排序
body = "" # GET请求无body
sign_str = f"{pathname}?{query}" if query else pathname
# Step 2: 构建签名密钥
timestamp = str(int(time.time()))
nonce = str(uuid.uuid4())
sign_key = f"appId={API_ID}&appSecret={API_SECRET}&timestamp={timestamp}&nonce={nonce}"
# Step 3: HMAC-SHA256计算签名
signature = hmac.new(
sign_key.encode('utf-8'),
sign_str.encode('utf-8'),
hashlib.sha256
).hexdigest()
# Step 4: 设置请求头
headers = {
"x-ca-key": API_ID,
"x-ca-sign": signature,
"x-ca-timestamp": timestamp,
"x-ca-nonce": nonce,
"Content-Type": "application/json;charset=UTF-8"
}
```
### 2.3 响应格式
```json
{
"code": "OK", // 成功="OK"V3/ 0V1);失败=错误码
"msg": "请求成功",
"traceId": "004c33070f4fa7b4",
"data": { ... }
}
```
> ⚠️ **注意**:V1接口(在线监控/终端管理)的 `code` 为数字(0=成功),V3接口(用户管理)的 `code` 为字符串("OK"=成功)。
---
## 3. 核心接口详解
### 3.1 P0 — 查询在线用户
| 项目 | 说明 |
|------|------|
| **路径** | `GET /api/v1/monitor/getUserStatus` |
| **用途** | 查询当前通过aTrust在线的用户列表 |
| **价值** | **获取远程办公员工的VPN会话信息,包括接入IP和虚拟IP** |
#### 请求参数
| 参数 | 必须 | 说明 | 示例 |
|------|------|------|------|
| pageSize | 是 | 每页大小,默认20 | 20 |
| pageIndex | 是 | 页码,从1开始 | 1 |
| filter | 否 | 过滤字段 | `name`/`remoteIp`/`os`/`browser`/`vip` |
| searchValue | 否 | 过滤搜索值 | `张三` |
| sortBy | 否 | 排序字段 | `lastLoginTime`/`remoteIp`/`vip` |
| asc | 否 | 1=升序,0=降序 | 1 |
#### 响应字段(关键字段加⭐)
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | string | **会话ID**(非用户ID,用于踢出操作) |
| `name` ⭐ | string | 用户名(登录名) |
| `displayName` | string | 显示名 |
| `userId` | string | 用户UUID |
| `remoteIp` ⭐ | string | 接入IP(公网IP或"内网IP" |
| `remoteIpLocation` ⭐ | string | IP归属地(如"内网IP"=从内网接入) |
| `os` | string | 操作系统 |
| `browser` | string | 接入方式(浏览器/客户端版本) |
| `lastLoginTime` ⭐ | string | 最后登录时间 |
| `domain` | string | 登录域 |
| `userDirectoryName` | string | 所属用户目录 |
| `groupPath` | string | 组织架构路径 |
| `isTrusted` ⭐ | number | 终端授信状态:0=未授信/1=已授信 |
> ⚠️ **关于`vips`(虚拟IP)字段**:在线文档(web版)的`getUserStatus`返回包含`vips[].ip`VPN虚拟内网IP),但官方docx文档的响应示例中**未展示此字段**。可能原因:1) docx为早期版本示例,新版API已新增;2) 需特定配置或隧道应用才返回。**对接时必须实际验证此字段是否存在**。若存在,则`vips[].ip`是远程终端接入内网的虚拟IP,可用于火绒交叉匹配。
#### 响应示例(官方docx版)
```json
{
"code": 0,
"data": {
"data": [{
"id": "33100014",
"name": "张三",
"groupPath": "/",
"os": "Windows 10",
"browser": "Chrome/104.0.5112.102",
"remoteIp": "175.9.142.2",
"remoteIpLocation": "内网IP",
"lastLoginTime": "2022-09-29 16:04:33",
"domain": "local",
"userId": "9f8146c0-8aeb-11ec-b30f-e50f6db6d9d6",
"userDirectoryName": "本地用户目录",
"isTrusted": 0,
"displayName": "显示名"
}],
"count": 1,
"pageSize": 20,
"pageIndex": 1,
"amount": 1,
"onlineUser": 1
},
"msg": "请求成功"
}
```
#### 业务解读
- `id`:**会话ID**,踢出用户时需使用此ID(非userId),支持精准踢出单个会话
- `remoteIp`:员工当前IP`remoteIpLocation="内网IP"`表示从内网直接接入(非VPN
- `isTrusted`:终端是否已授信,0=未授信可能影响访问权限
- `name`:用户登录名,如果与公司域账号一致,则可直接映射到 `employee_id`
- 同一用户可能在多个终端登录,返回多条记录(每条有不同`id`
---
### 3.2 P0 — 查询全量终端信息
| 项目 | 说明 |
|------|------|
| **路径** | `POST /api/v1/device/queryAll` |
| **用途** | 批量查询aTrust纳管的终端设备 |
| **价值** | **按绑定用户查询终端列表,建立用户→终端映射** |
#### 请求参数
| 参数 | 必须 | 类型 | 说明 |
|------|------|------|------|
| bindUserList | 否 | object[] | **按绑定用户过滤**v2.6.6+ |
| ├─ userName | 是 | string | 用户名 |
| ├─ userDirectoryName | 是 | string | 用户目录名 |
| onlineStatus | 否 | number | 0=离线,1=在线 |
| loginStatus | 否 | number | 0=未接入,1=已接入 |
| assetType | 否 | string | CYOD/BYOD/COPE/NONE |
| trusted | 否 | number | 0=未授信,1=已授信 |
| tagList | 否 | string[] | 标签过滤 |
| osList | 否 | string[] | OS过滤(Windows/macOS/统信UOS/麒麟Kylin/Android/iOS/HarmonyOS/iPadOS |
| pageSize | 否 | number | 最大1000 |
| pageIndex | 否 | number | 默认1 |
#### 响应字段(关键字段加⭐)
| 字段 | 类型 | 说明 |
|------|------|------|
| `externalId` ⭐ | string | 终端外部ID(唯一标识) |
| `macList` ⭐ | string[] | MAC地址列表 |
| `deviceName` ⭐ | string | 终端名称/主机名 |
| `os` | string | 操作系统 |
| `deviceType` | string | PC/Mobile |
| `deviceBrand` | string | 品牌 |
| `assetType` | string | CYOD(企业)/BYOD(个人)/COPE(纳管) |
| `trusted` ⭐ | number | 授信状态:0=未授信/1=已授信 |
| `onlineStatus` ⭐ | number | 在线状态 |
| `loginStatus` ⭐ | number | 接入状态 |
| `tagList` | string[] | 标签列表 |
| `windowsDomain` | string | Windows域控 |
| `bindUsers` ⭐ | object[] | **绑定用户列表** |
| ├─ bindUser | string | 绑定的用户名 |
| ├─ bindType | string | 绑定方式:userSelfBind/adminBind/adminAdmit |
| ├─ bindTime | string | 绑定时间 |
| `historyUsers` | object[] | 历史登录用户列表 |
| `lastLoginUser` | string | 最后登录用户名 |
| `displayName` | string | 最后登录用户显示名 |
| `clientVersion` | string | 客户端版本 |
| `lastLoginTime` | string | 最后接入时间 |
| `lastActiveTime` | string | 最后活跃时间 |
> ⚠️ **重要**aTrust终端接口**不返回IP地址**,只有 `lastNetworkZone`(网络区域标识,如"内网IP")。需通过在线监控接口(4.1.1)获取VPN IP。
---
### 3.3 P0 — 查询单个终端信息
| 项目 | 说明 |
|------|------|
| **路径** | `GET /api/v1/device/query` |
| **用途** | 按externalId或MAC查询单个终端详情 |
| **约束** | externalId和mac互斥,不可同时传入 |
#### 请求参数
| 参数 | 必须 | 说明 |
|------|------|------|
| externalId | 二选一 | 终端外部ID |
| mac | 二选一 | MAC地址(匹配多条则报错) |
#### 额外响应字段(相比queryAll,来自官方docx
| 字段 | 类型 | 说明 |
|------|------|------|
| `idleTime` ⭐ | number | 终端闲置时长(天),可用于判断长期离线设备 |
| `firstImportTime` | string | 首次录入时间 |
| `lastLoginMethod` | string | 最后接入方式(如"Edge/98.0.1108.50" |
| `lastLoginNetZone` ⭐ | string | 最后接入网络区域("内网IP"/外网标识) |
| `userDescription` | string | 最后登录用户描述 |
| `path` | string | 最后登录用户所属组织架构 |
| `lastActiveTime` | string | 最后活跃时间 |
| `clientVersion` | string | aTrust客户端版本 |
| `windowsDomain` ⭐ | string | Windows域控名(可用于AD域映射) |
| `deviceBrand` | string | 设备品牌 |
| `historyUsers` ⭐ | object[] | **历史登录用户列表**(含userName/userDirectoryName/displayName/userDescription |
> 💡 `historyUsers`字段非常有价值:即使终端当前未绑定用户,通过历史登录记录也能追溯设备使用者,辅助员工→终端映射。
---
### 3.4 P1 — 踢出在线用户
| 项目 | 说明 |
|------|------|
| **路径** | `POST /api/v1/monitor/kickoutUsers` |
| **用途** | 强制断开VPN会话 |
| **安全等级** | 🔴 高危操作,必须二次确认+审计日志 |
#### 请求参数(二选一)
| 方式 | 参数 | 说明 |
|------|------|------|
| **按会话ID** | `idList: string[]` | 从查询在线用户接口获取的会话ID,精准踢出单个会话 |
| **按用户名** | `userList: [{name, userDirectoryName}]` | ⚠️ **该用户所有终端的会话都会被踢出** |
#### 安全约束(与火绒隔离同级)
- 踢出操作**必须人工二次确认 + 填写原因**
-**admin角色** 可执行
- 操作记录写入审计日志
- 优先使用 `idList`(精准踢出),避免误伤其他终端
---
### 3.5 P1 — 查询用户详情
| 项目 | 说明 |
|------|------|
| **路径** | `GET /api/v3/user/queryByName` |
| **用途** | 按用户名查询用户详情 |
#### 关键响应字段
| 字段 | 说明 | 与IT服务台映射 |
|------|------|---------------|
| `name` | 用户登录名 | 可能对应 `employee_id` |
| `externalId` ⭐ | 外部ID | **可设置为工号,直接映射** |
> ⚠️ **V3 API关键参数 `directoryDomain`**:所有V3用户管理API必须传入`directoryDomain`参数(用户目录域名),例如`"custom01339"`或`"local"`。此值需从aTrust控制台的【系统管理/用户目录】页面获取,或在首次对接时通过`4.8.1 查询用户目录列表`接口获取。不同用户目录(本地/LDAP/外部同步)有不同的`directoryDomain`。
| `displayName` | 显示名 | 员工姓名 |
| `groupPath` | 组织架构路径 | 部门信息 |
| `email` | 邮箱 | 联系方式 |
| `phone` | 手机号 | 联系方式 |
| `status` | 启用/禁用 | 账号状态 |
| `roleIdList` | 角色ID列表 | 权限信息 |
| `resourceIdList` | 关联应用ID列表 | 有权限访问的应用 |
---
### 3.6 P1 — 终端绑定/解绑用户
| 项目 | 说明 |
|------|------|
| **绑定路径** | `POST /api/v1/device/assignUser` |
| **解绑路径** | `POST /api/v1/device/unassignUser` |
#### 绑定参数
| 参数 | 说明 |
|------|------|
| externalId 或 mac | 终端标识(二选一) |
| userName | 用户名 |
| userDirectoryName | 用户目录名 |
#### 绑定方式
| 方式 | 说明 |
|------|------|
| `userSelfBind` | 用户自助绑定 |
| `adminBind` | 管理员手动绑定 |
| `adminAdmit` | 管理员审批后绑定 |
> 💡 可通过OpenAPI实现联软/eHR的终端绑定数据同步到aTrust。
---
### 3.7 P2 — 终端CRUD管理(官方docx新增)
| 操作 | 路径 | 方法 | 版本要求 | 说明 |
|------|------|------|---------|------|
| 新增终端 | `/api/v1/device/create` | POST | v2.2.7+ | MAC/计算机名+externalId |
| 修改终端 | `/api/v1/device/update` | POST | v2.2.9+ | 基于externalId修改,支持newExternalId |
| 删除终端 | `/api/v1/device/delete` | POST | v2.2.7+ | 基于externalId或MAC删除 |
#### 终端匹配规则
aTrust判断终端是否已存在的规则:
1. `externalId`匹配已有终端
2. 根据控制台【终端匹配规则】,MAC或计算机名与已有终端一致
#### 新增终端请求示例
```json
{
"mac": ["FE-FC-FE-21-F5-D1", "FE-FC-FE-21-F5-D2"],
"deviceType": "PC",
"name": "DESKTOP-I3ABQBS",
"externalId": "0c4e9039-f81d-11ec-a760-fefcfe545bb7",
"assetType": "BYOD",
"tagList": ["开发测试终端", "办公网终端"]
}
```
> 💡 `assetType`选项:CYOD(企业选型)/ BYOD(自带)/ COPE(纳管)/ NONE。可通过`externalId`与联软终端ID对齐。
### 3.8 P2 — 终端标签管理
| 项目 | 说明 |
|------|------|
| 设置标签 | `POST /api/v1/device/setTag`(支持追加`isAppend=1`或覆盖模式) |
| 取消标签 | `POST /api/v1/device/unsetTag` |
标签不存在时自动新增。可用于标注终端类型(如"开发测试终端"、"办公网终端"),与IT服务台的设备分类对齐。
### 3.9 P2 — SPA安全码管理
| 项目 | 说明 |
|------|------|
| **路径** | `POST /api/v1/spa/sendSpaCode` |
| **版本** | v2.2.10+ |
| **用途** | 为指定用户申请SPA安全码(单包授权),通过短信发送 |
> 💡 SPASingle Packet Authorization)安全码是零信任中"先认证后连接"机制的关键。当员工报修"无法访问内网应用"时,坐席可通过此接口为其重新发送安全码,恢复VPN接入能力。
#### 请求参数
| 参数 | 说明 |
|------|------|
| name/displayName/phone/email | 至少传一个(联合查询用户) |
| userDirectoryName | 必传(用户目录名) |
| expiredTime | 过期时间戳(秒),0=永不过期 |
| sendMode | 发送方式:`["sms"]`(暂仅支持短信) |
---
### 3.10 API版本兼容性说明
> ⚠️ aTrust不同API端点的版本要求不同,对接前必须确认公司aTrust版本。
| API模块 | 最低版本 | 说明 |
|---------|---------|------|
| 在线监控(4.1 | 未标注 | 可能v2.2.x+即可 |
| 终端管理-基础(create/delete/queryAll | **v2.2.7** | |
| 终端管理-高级(update/query/assignUser/unassignUser/setTag | **v2.2.9** | |
| SPA安全码 | **v2.2.10** | |
| V3用户管理(4.2~4.8 | **v2.4.10** | 用户/组织架构/角色/应用管理 |
> **关键判断**:如果公司aTrust版本 < v2.2.9,则终端绑定用户功能不可用,映射策略需调整。
---
## 4. 集成架构设计
### 4.1 四系统联合映射架构(最终版)
```
┌─────────────────┐
│ IT智能服务台 │
│ employee_id │
└────────┬────────┘
┌────────────────┼────────────────┐
↓ ↓ ↓
┌─────────────────┐ ┌────────────────┐ ┌────────────────┐
│ 联软LV7000(主源)│ │ aTrust(VPN源) │ │ eHR(辅助源) │
│ │ │ │ │ │
│ queryDevByParams│ │ 4.1.1 在线用户 │ │ 员工基础信息 │
│ strusername= │ │ name= │ │ 任职信息 │
│ employee_id │ │ employee_id │ │ 部门/职位 │
│ │ │ │ │ │
│ → 终端MAC/IP │ │ → remoteIp │ │ → 员工姓名 │
│ → 硬件详情 │ │ → vips[].ip │ │ → 联系方式 │
│ → 准入状态 │ │ → os/browser │ │ → 上级主管 │
│ → 在线状态 │ │ → loginTime │ │ │
└────────┬────────┘ └────────┬───────┘ └─────────────────┘
│ │
│ 用IP/MAC交叉匹配 │
↓ ↓
┌─────────────────────────────────────┐
│ 火绒企业版(安全源) │
│ │
│ _list(ip=终端IP) → client_id │
│ _info2 → 病毒事件/高危漏洞/安全评分 │
│ _virus_events → 病毒统计 │
│ _leak → 高危漏洞未修复 │
│ _create(netctrl) → 一键隔离 │
└─────────────────────────────────────┘
```
### 4.2 映射优先级与数据源选择
| 接入场景 | 首选数据源 | 查询路径 | 覆盖率 |
|---------|-----------|---------|--------|
| **总部内网办公** | 联软(主源) | `queryDevByParams(strusername=id)` → IP/MAC → 火绒安全状态 | ~95% |
| **远程/出差** | aTrust(VPN源) | `getUserStatus(name=id)` → vips[].ip → 火绒安全状态 | ~90% |
| **历史/离线** | 联软+aTrust | 联软历史记录 + aTrust historyUsers | ~80% |
| **新入职** | eHR(辅助) | eHR员工信息 → 手动关联终端 | ~0% |
### 4.3 完整查询流程
```
1. 坐席/员工输入 employee_id
2. 并行查询:
├── 联软 queryDevByParams(strusername=employee_id) → 内网终端列表
├── aTrust getUserStatus(name=employee_id) → VPN在线会话
└── aTrust queryAll(bindUserList=[{userName=id}]) → VPN绑定终端
3. 合并终端列表(去重,以MAC为主键)
4. 用合并后的IP/MAC列表查火绒安全状态
5. 组装「终端安全画像」返回给坐席/员工
```
### 4.4 aTrust与联软映射对比
| 维度 | 联软LV7000 | aTrust |
|------|-----------|--------|
| **映射字段** | `strusername`(直接是员工账号) | `name`(用户名)+ `bindUsers[].bindUser` |
| **映射准确度** | ⭐⭐⭐⭐⭐ 总部必装,100%覆盖 | ⭐⭐⭐⭐ 依赖绑定策略 |
| **IP地址** | ✅ 有内网IP | ✅ 有公网IP + VPN虚拟IP |
| **MAC地址** | ✅ strmac | ✅ macList(数组) |
| **硬件详情** | ✅ 极详细(磁盘/内存/显示器) | ❌ 仅基础信息 |
| **远程终端** | ⚠️ 可能未覆盖 | ✅ 核心覆盖VPN终端 |
| **实时在线** | ✅ existOnlineUser | ✅ onlineStatus + getUserStatus |
| **组织架构** | ✅ 组织架构查询 | ✅ groupPath + 组织架构API |
---
## 5. 产品维度分析
### 5.1 场景匹配度
| IT服务台场景 | aTrust能做什么 | 匹配度 |
|-------------|---------------|--------|
| 员工报修"远程无法访问内网" | 查询VPN在线状态+虚拟IP+接入方式 | ⭐⭐⭐⭐⭐ |
| 坐席排查"VPN连接异常" | 查询在线状态、最后登录时间、接入IP | ⭐⭐⭐⭐⭐ |
| 安全应急"发现可疑VPN连接" | 踢出在线用户(断开VPN会话) | ⭐⭐⭐⭐⭐ |
| 终端排查"设备是否授信" | 查询终端trusted状态+绑定用户 | ⭐⭐⭐⭐ |
| AI推送"VPN连接诊断" | 获取VPN会话信息供AI分析 | ⭐⭐⭐⭐ |
| 员工自助"查看VPN状态" | 查询自己是否在线+虚拟IP | ⭐⭐⭐ |
### 5.2 功能规划
#### P0 — 查询能力(零风险,~1.5周)
| 功能 | 使用接口 | 说明 |
|------|---------|------|
| VPN在线状态查询 | 4.1.1 getUserStatus | 坐席查看员工VPN连接状态 |
| 远程终端查询 | 4.9.5 queryAll(bindUserList) | 按员工查询VPN绑定终端 |
| 终端安全画像集成 | 4.9.4 query + 火绒/联软 | aTrust终端信息加入画像 |
#### P1 — 控制能力(中风险,~1周)
| 功能 | 使用接口 | 安全约束 |
|------|---------|---------|
| 踢出VPN会话 | 4.1.2 kickoutUsers | admin角色+二次确认+审计 |
| 终端授信标签同步 | 4.9.8/4.9.9 setTag/unsetTag | 与联软准入状态同步 |
#### P2 — 管理能力(低风险,~1周)
| 功能 | 使用接口 | 说明 |
|------|---------|------|
| 用户同步 | 4.2.x 用户管理API | eHR→aTrust用户同步 |
| 终端绑定同步 | 4.9.6 assignUser | 联软映射→aTrust绑定 |
| 安全态势看板 | 4.1.1+4.9.5 | 管理后台VPN在线统计 |
---
## 6. 开发维度分析
### 6.1 技术架构
```
backend/app/
├── integrations/
│ ├── atrust/
│ │ ├── __init__.py
│ │ ├── client.py # aTrust API客户端(签名+请求)
│ │ ├── models.py # 数据模型(ATrustUser/ATrustTerminal/ATrustSession
│ │ ├── cache.py # 缓存策略
│ │ └── service.py # 业务服务层
│ ├── huorong/
│ │ └── ... (已有)
│ ├── leagsoft/
│ │ └── ... (已有)
│ └── device_profile.py # 四系统聚合 → 终端安全画像
├── api/
│ └── integrations.py # 统一对外API
```
### 6.2 签名实现
aTrust签名比火绒复杂(4步),但逻辑清晰:
> **与火绒签名的关键区别**:火绒使用HMAC-SHA1aTrust使用HMAC-SHA256;火绒签名放在Header和URL两种方式,aTrust仅Header方式;aTrust签名密钥包含timestamp和nonce(更安全)。
```python
# backend/app/integrations/atrust/client.py
import hmac, hashlib, uuid, time, httpx
from urllib.parse import urlparse, parse_qs
class ATrustClient:
def __init__(self, base_url: str, api_id: str, api_secret: str):
self.base_url = base_url # https://atrust.xxx.com:4433
self.api_id = api_id
self.api_secret = api_secret
self.client = httpx.AsyncClient(verify=False, timeout=30)
def _build_sign_str(self, method: str, path: str, query: str, body: str) -> str:
"""
构建签名串:pathname?sorted_query&compact_body
- query的key必须按ASCII排序
- body必须是紧凑JSON(无空格/换行)
"""
parts = [path]
if query or body:
parts.append("?")
if query:
# 对query参数按key排序
parsed = parse_qs(query)
sorted_query = "&".join(
f"{k}={v[0]}" for k, v in sorted(parsed.items())
)
parts.append(sorted_query)
if query and body:
parts.append("&")
if body:
parts.append(body)
return "".join(parts)
def _sign(self, sign_str: str) -> tuple[str, str, str]:
"""4步签名:生成签名密钥 → HMAC-SHA256 → 返回签名+时间戳+nonce"""
timestamp = str(int(time.time()))
nonce = str(uuid.uuid4())
# 签名密钥
sign_key = (
f"appId={self.api_id}&appSecret={self.api_secret}"
f"&timestamp={timestamp}&nonce={nonce}"
)
# HMAC-SHA256
signature = hmac.new(
sign_key.encode("utf-8"),
sign_str.encode("utf-8"),
hashlib.sha256,
).hexdigest()
return signature, timestamp, nonce
async def request(self, method: str, path: str, **kwargs) -> dict:
"""通用请求方法:自动签名"""
url = f"{self.base_url}{path}"
parsed = urlparse(url)
query = parsed.query
body = ""
if kwargs.get("json"):
body = json.dumps(kwargs["json"], separators=(",", ":"))
sign_str = self._build_sign_str(method, parsed.path, query, body)
signature, timestamp, nonce = self._sign(sign_str)
headers = {
"x-ca-key": self.api_id,
"x-ca-sign": signature,
"x-ca-timestamp": timestamp,
"x-ca-nonce": nonce,
"Content-Type": "application/json;charset=UTF-8",
}
response = await self.client.request(
method, url, headers=headers, **kwargs
)
return response.json()
```
### 6.3 缓存策略
| 数据类型 | 缓存时间 | 理由 |
|---------|---------|------|
| VPN在线状态 | **不缓存**(实时查询) | 实时性要求高 |
| 终端绑定信息 | 30分钟 | 绑定变更不频繁 |
| 用户信息 | 1小时 | 用户信息变更极少 |
| 组织架构 | 4小时 | 几乎不变 |
### 6.4 与其他系统的交叉匹配
```python
# 终端安全画像聚合伪代码
async def get_device_profile(employee_id: str) -> DeviceProfile:
# 1. 并行查三系统
leagsoft_task = leagsoft.query_dev_by_params(strusername=employee_id)
atrust_task = atrust.get_online_users(name=employee_id)
atrust_terminals_task = atrust.query_all_terminals(
bindUserList=[{"userName": employee_id, "userDirectoryName": "local"}]
)
leagsoft_devs, atrust_sessions, atrust_terminals = await asyncio.gather(
leagsoft_task, atrust_task, atrust_terminals_task
)
# 2. 收集所有IP/MAC
all_ips = set()
all_macs = set()
for dev in leagsoft_devs:
all_ips.add(dev.strip)
all_macs.add(dev.strmac.upper().replace(":", "-"))
for session in atrust_sessions:
all_ips.add(session.remoteIp)
for vip in session.vips:
all_ips.add(vip.ip)
for terminal in atrust_terminals:
for mac in terminal.macList:
all_macs.add(mac.upper())
# 3. 查火绒安全状态
huorong_tasks = []
for ip in all_ips:
huorong_tasks.append(huorong.list_clients(ip=ip))
huorong_results = await asyncio.gather(*huorong_tasks)
# 4. 组装画像
return DeviceProfile(
employee_id=employee_id,
leagsoft_devices=leagsoft_devs,
atrust_sessions=atrust_sessions,
atrust_terminals=atrust_terminals,
huorong_security=huorong_results,
)
```
---
## 7. 安全维度分析
### 7.1 认证安全
| 风险 | 等级 | 缓解措施 |
|------|------|---------|
| API密钥泄露 | 🔴 高 | 环境变量存储,禁止写入代码;定期轮换 |
| 签名重放攻击 | 🟢 低 | timestamp+nonce防重放(已内置) |
| 中间人攻击 | 🟢 低 | 强制HTTPS |
| IP白名单绕过 | 🟡 中 | 白名单仅包含IT服务台服务器IP |
### 7.2 操作安全
| 操作 | 风险 | 安全约束 |
|------|------|---------|
| **踢出在线用户** | 🔴 高危 | admin角色 + 二次确认 + 填写原因 + 审计日志 |
| 终端绑定/解绑 | 🟡 中 | admin角色 + 操作日志 |
| 查询在线用户 | 🟢 低 | 只读操作,无风险 |
| 查询终端信息 | 🟢 低 | 只读操作,注意不向H5用户端暴露MAC等敏感信息 |
### 7.3 数据安全
| 数据类型 | H5用户端是否可见 | 说明 |
|---------|----------------|------|
| VPN在线状态 | ✅ 可见(自己的) | "您当前VPN连接正常" |
| 虚拟IP | ❌ 不显示 | 内网敏感信息 |
| 接入IP | ❌ 不显示 | 公网IP属于隐私 |
| 终端MAC | ❌ 不显示 | 设备指纹,敏感 |
| 终端授信状态 | ✅ 可见(简化版) | "您的设备已通过安全认证" |
| 绑定用户列表 | ❌ 不显示 | 其他用户的绑定信息 |
### 7.4 与火绒隔离的统一安全框架
| 安全规则 | 火绒网络隔离 | aTrust踢出用户 |
|---------|------------|---------------|
| 执行角色 | 仅admin | 仅admin |
| 操作确认 | 二次确认弹窗 | 二次确认弹窗 |
| 原因记录 | 必填+审计日志 | 必填+审计日志 |
| 通知机制 | 通知被隔离用户 | 通知被踢出用户 |
| 可逆性 | 可解除隔离 | 用户可重新登录 |
---
## 8. 对接前检查清单
### 8.1 必须确认
- [ ] aTrust版本确认(必须≥2.4.10才支持V3 API;终端管理高级功能需≥v2.2.9)
- [ ] 获取API ID和API密钥
- [ ] IT服务台服务器IP加入aTrust白名单
- [ ] 确认aTrust用户目录类型(本地/LDAP/外部)及 `directoryDomain`
- [ ] 确认aTrust中用户名(`name`)是否与公司域账号/企微账号一致
- [ ] 确认`externalId`字段用途(是否可设置为工号)
- [ ] **验证`getUserStatus`接口是否返回`vips`字段**(docx版未展示,web版有,需实测确认)
- [ ] 确认8 QPS限频是否满足业务需求(估计足够)
### 8.2 建议确认
- [ ] aTrust终端绑定策略(是否开启一对一绑定)
- [ ] 在线用户数据保留时长(历史VPN会话是否可查)
- [ ] API调用频率限制
- [ ] 是否有API调用审计日志
### 8.3 需找团队
| 对接方 | 需获取 | 预估时间 |
|--------|--------|---------|
| **信息安全团队** | API ID/密钥、白名单配置、版本确认 | 1-2天 |
| **网络运维团队** | aTrust部署架构、用户目录配置 | 1天 |
| **终端安全团队** | 联软+aTrust+火绒统一映射策略对齐 | 2-3天 |
---
## 9. 四系统协同方案总结
### 9.1 系统定位矩阵
| 系统 | 定位 | 核心价值 | 不可替代性 |
|------|------|---------|-----------|
| **联软LV7000** | 终端管理(主源) | 员工→终端映射 + 硬件详情 + 准入控制 | ⭐⭐⭐⭐⭐ strusername精确映射 |
| **aTrust** | 远程接入(VPN源) | VPN会话数据 + 远程终端映射 + 踢出能力 | ⭐⭐⭐⭐⭐ 唯一VPN数据源 |
| **火绒企业版** | 终端安全(安全源) | 病毒/漏洞/隔离 + 安全评分 | ⭐⭐⭐⭐⭐ 唯一安全数据源 |
| **北森eHR** | 人事数据(辅助源) | 员工基础信息 + 任职 + 组织架构 | ⭐⭐⭐ 员工主数据 |
### 9.2 数据流向
```
员工报修 → employee_id
联软 → 内网终端列表 (IP/MAC/硬件)
aTrust → VPN终端列表 (remoteIp/vips/macList)
↓ 合并去重
火绒 → 安全状态 (病毒/漏洞/隔离)
eHR → 员工信息 (姓名/部门/主管)
组装「终端安全画像」→ 展示给坐席/员工
```
### 9.3 接口调用频次估算
| 场景 | 调用次数 | 触发频率 |
|------|---------|---------|
| 员工发起报修 | 联软1 + aTrust2 + 火绒1~3 = 4~6次 | 按需(每天几十次) |
| 坐席查看终端画像 | 同上 | 按需 |
| 安全态势看板 | aTrust1 + 火绒1 | 定时刷新(5分钟) |
| 终端映射全量同步 | 联软1 + aTrust1 | 每天凌晨1次 |
### 9.4 实施优先级
| 优先级 | 内容 | 周期 | 依赖 |
|--------|------|------|------|
| **P0** | aTrust查询能力上线 | ~1.5周 | API ID/密钥 + 白名单 |
| **P1** | 踢出用户+标签同步 | ~1周 | P0完成 |
| **P2** | 四系统联合画像 | ~1.5周 | 联软+火绒+eHR已集成 |
| **P3** | 用户同步自动化 | ~1周 | eHR→aTrust对接流程确认 |
---
## 附录
### A. aTrust vs 火绒 vs 联软 — 技术对比
| 维度 | 联软LV7000 | 火绒企业版 | aTrust |
|------|-----------|-----------|--------|
| API端点数 | 68 | 17 | 104 |
| 认证方式 | IP白名单+账号密码+Token | AccessKey+HMAC-SHA1 | API_ID+HMAC-SHA256 |
| 签名复杂度 | 简单(Base64编码) | 中等(HMAC-SHA1 | 较高(4步签名) |
| 协议 | HTTP | HTTPS | HTTPS(4433) |
| 响应格式 | {code, data, msg} | {errno, errmsg, data} | {code, msg, data, traceId} |
| 成功标识 | code=0 | errno=0 | code=0(V1)/"OK"(V3) |
| 分页 | pageSize+pageIndex | page+pageSize | pageSize+pageIndex |
| 最大分页 | 500 | 500 | 1000 |
| IP地址 | ✅ 有 | ✅ 有 | ✅ 有(remoteIp+vips*) |
| MAC地址 | ✅ strmac | ❌ 无 | ✅ macList |
| 员工→终端映射 | ⭐⭐⭐⭐⭐ strusername | ⭐⭐ 需IP交叉匹配 | ⭐⭐⭐⭐ name+bindUsers+historyUsers |
| 频率限制 | 未标注 | 未标注 | **8 QPS** |
| 历史用户 | ❌ 无 | ❌ 无 | ✅ historyUsers(追溯设备使用者) |
> *vips字段在web版文档中有,docx版未展示,需实测确认
### B. aTrust关键API速查表
| 接口 | 路径 | 方法 | P级 |
|------|------|------|------|
| 查询在线用户 | /api/v1/monitor/getUserStatus | GET | P0 |
| 踢出在线用户 | /api/v1/monitor/kickoutUsers | POST | P1 |
| 新增终端 | /api/v1/device/create | POST | P2 |
| 修改终端 | /api/v1/device/update | POST | P2 |
| 删除终端 | /api/v1/device/delete | POST | P2 |
| 查询全量终端 | /api/v1/device/queryAll | POST | P0 |
| 查询单个终端 | /api/v1/device/query | GET | P0 |
| 终端绑定用户 | /api/v1/device/assignUser | POST | P1 |
| 终端解绑用户 | /api/v1/device/unassignUser | POST | P1 |
| 设置终端标签 | /api/v1/device/setTag | POST | P2 |
| 取消终端标签 | /api/v1/device/unsetTag | POST | P2 |
| 查询用户详情 | /api/v3/user/queryByName | GET | P1 |
| 查询用户列表 | /api/v3/user/queryAll | POST | P1 |
| 申请SPA安全码 | /api/v1/spa/sendSpaCode | POST | P2 |