← TELOA BLOG

安全研究 · 2026年10月11日 · Max Luo

智能体身份:分清用户、Agent 与执行实例

由 Teloa AI Security 维护 · 智能体安全基线系列

作者:Max Luo · 2026年10月11日 · Teloa AI Security

请求里有 user_id,不代表请求已经通过用户认证;进程有一个 Agent 名称,不代表它被平台允许以这个身份访问下游。企业 Agent 的身份设计要回答三个不同的问题:谁发起并承担授权责任,哪一个逻辑 Agent 正在执行,哪一个运行实例持有这次调用的证明。

这篇文章沿“员工从 IM 发起工单摘要任务”的路径,设计身份绑定、执行实例登记、网关认证和停用流程。JSON 与流程都是参考设计,示例字段不是标准协议,也不代表 Teloa 已实现全部控制。规范依据是基线 V1,等级与适用条件按原文核验。

1. 建立三个身份,再关联任务与租户

身份 例子与可信来源 生命周期 能证明什么
用户主体 IdP 验证后映射的 user-42 入职、转岗、离职及认证会话 哪个人发起或委托了任务
逻辑 Agent 平台登记的 agent-support 登记、发布、配置变更、停用 使用哪项受控 Agent 配置
工作负载 控制面签发给 run-17 的短期身份 单次会话或执行实例 哪个实例正在发起访问

任务、租户、工作空间、连接器与这三个身份形成平台登记关系。它们不能在每次请求中被自由组合:一个合法的 run-17 凭证,也不能被请求参数重新绑定给管理员或另一个租户。负责人是治理属性,不能代替执行主体。

这里还要区分代表用户行事与自主 Agent。代表用户的 Agent 受该用户权限上限约束;基线中的自主 Agent 使用独立的非人类身份,负责人负责治理,但平台不能偷借负责人的个人账号。自动程度很高的定时任务,也可能仍然属于用户委托任务。V1.3.2、V2.3 对这两种模式分别规定了身份与权限责任。

2. 渠道绑定要证明双方,而不是匹配名字

一个安全的绑定流程必须同时证明“这个渠道账号是谁”和“这个企业用户是谁”。只完成 SSO,然后相信浏览器传回的 IM 用户 ID,仍然可能把攻击者的渠道账号绑定到受害人的企业身份。

一种参考流程是:

  1. 验证渠道平台签名、时间戳和事件去重标识,从已验证事件得到组织 ID 与稳定的渠道账号 ID。
  2. 服务端创建短时、单次使用的绑定事务,记录渠道组织、账号、预期企业租户及回调状态;浏览器只拿到随机事务引用。
  3. 用户进入企业 IdP 完成认证,平台验证登录结果与绑定事务。采用 OIDC 授权码流程时,按协议完成 state、nonce 与 PKCE 等检查,不能用未经校验的令牌载荷建立绑定。
  4. 根据已验证的 IdP 身份查企业目录,确认用户仍启用、租户一致。在已认证的企业用户界面展示服务端固定的渠道组织与账号,要求用户明确确认绑定意图;再核对渠道账号所有权,在原渠道完成确认或采用提供方可验证的账号关联机制。不能只有攻击者能够独立完成的原渠道确认,否则转交绑定链接可诱导受害人登录并关联到攻击者的账号。
  5. 原子消费事务并建立绑定;换绑、跨租户绑定和账号恢复需要重新验证,旧绑定的解除留审计。

企业用户键可以由可信 issuer 与 subject 映射产生。OpenID Connect Core规定 sub 在签发方内识别用户,并存在 pairwise subject 模式。因此跨客户端不能假定 sub 相同,更不能退回用邮箱字符串自动合并账号。

{
  "channel_key": ["im-provider", "org-a", "channel-user-81"],
  "enterprise_user": "user-42",
  "verified_idp_identity": {
    "issuer": "https://idp.corp.example",
    "subject": "idp-subject-4281"
  },
  "tenant": "tenant-a",
  "binding_transaction": "bind-902",
  "status": "active"
}

这是服务端登记记录,不是接受任意客户端提交的绑定请求。显示名、昵称和邮件 From 地址只能用于展示。DMARC 校验可以帮助核验发件域,却不能单独证明企业员工身份,也不能代替企业授权;邮件渠道还必须满足 V1.2.6 的外部域限制和其他身份控制。

3. 执行实例启动时固定身份关系

在创建 run-17 时,控制面先验证用户状态与 Agent 配置,再登记 tenant-a / user-42 / agent-support / task-17 / run-17 的关系。凭证的持有边界要与模型、可执行代码及普通工具结果分开。

已验证渠道事件 → 查询绑定与用户状态
              → 控制面创建任务、登记 run-17
              → 签发受众受限的短期工作负载证明
              → 受控身份组件认证到出口网关
              → 网关查实例登记,恢复可信调用主体

如果使用 JWT,可以采用下面这种平台内部证明载荷。这里的私有声明只是为了展示绑定关系;它不是 ID Token,也不是可以直接传给第三方 SaaS 的通用 OAuth 令牌。示例时长为 300 秒,是演示选择,不是基线要求的统一时长。

{
  "iss": "https://workload-issuer.corp.example",
  "sub": "workload:run-17",
  "aud": "egress-gateway",
  "iat": 1791676800,
  "exp": 1791677100,
  "jti": "proof-017",
  "tenant_id": "tenant-a",
  "task_id": "task-17",
  "registry_revision": 7
}

网关不能只验签。它还要限制可信签发方、算法和密钥来源,验证受众、有效期与所选令牌类型,并检查实例仍处于活动状态、任务与登记版本一致。kid 只用于选择预先信任的密钥,不允许请求提供任意验签地址。权限与用户启用状态来自当前控制面,不能永远使用签发时的副本。

如果部署采用 OAuth JWT access token profile,应遵循 RFC 9068 的资源服务器校验规则,而不是将上述私有证明伪装成标准访问令牌。JWT 的签名保证完整性,不保证载荷保密;Base64 解码得到的声明不能作为已验证身份。

4. 在网关恢复主体,处理代理与 sidecar 的边界

V1.4.3 要求网关只依据工作负载身份确定用户和 Agent。一个安全的处理顺序是认证工作负载、查可信登记、检查状态,再将恢复的主体交给策略服务。工具参数中的 user_id、agent_id 只能作为待校验业务数据,不能覆盖认证结果。

常见的绕过发生在反向代理里:代理设置了 X-User-ID,但网关也允许客户端直接访问,并接受同名请求头。修复必须包含网络访问限制、可信代理认证,以及移除或覆盖客户端自带的身份头。只修改代码中“优先读取哪个头”不够。

sidecar 可以把密钥与模型上下文分开,但不自动构成安全边界。如果任意沙箱进程都能访问 sidecar 的身份签名接口,失陷进程仍可能以该实例身份提出请求。应限制控制接口和文件权限,阻断跨实例借用;同时假定已认证实例可能是恶意调用者,继续做每次请求的资源级授权。

工作负载认证的意义是“确定谁在调用”,不能证明“它的调用内容是安全的”。这一点也是身份篇与下一篇授权篇的分工。

5. 使用工作负载证明时,区分身份与软件完整性

V1.4.5 将签发前的工作负载证明放在 L3。SPIRE 的概念文档区分节点证明与工作负载证明:前者识别运行节点,后者利用进程属性与登记条件识别工作负载。这提供了签发身份的可信依据。

工程上还要处理实例粒度。若全部容器复用同一个服务级 SPIFFE ID,网关只能识别“这个服务”,不能据此区分具体会话。可以为会话建立独立登记关系,或通过受控 broker 在已证明的服务身份上再绑定一次性执行实例上下文;绑定仍须由控制面生成。

证明也不等于代码从未被攻陷。镜像签名、依赖版本锁定和运行时隔离分别解决供应链与执行问题,不能靠一个有效证书替代。L1、L2 部署也要满足其适用的短期实例身份要求,但不应被本文错误地提升为必须安装 SPIRE。

6. 下游令牌表达用户与执行者,委托链不增加权限

网关访问下游时,需要把内部工作负载身份转换成下游认可的授权形式。RFC 8693中的 sub 与 act 可以分别表达主体和当前执行者。以下仅展示声明关系,实际令牌由可信授权服务器签发,资源范围、有效期和受众按下游协议确定。

{
  "sub": "user-42",
  "aud": "tickets-api",
  "scope": "tickets:read",
  "act": { "sub": "agent-support" }
}

嵌套 act 保存先前执行者的历史,不是可以累加的授权集合。RFC 8693 明确历史执行者不能用于资源服务器的访问控制决定。多跳委托的权限收窄应在可信授权与策略服务中完成,将最终范围写入当前有效授权;审计保存完整链路,而不是从链中找到一个管理员就放行。

令牌交换也不会自动防止越权。授权服务器仍需判断谁可以代表谁、允许访问哪个资源,以及本次委托是否有效。自主 Agent 则使用自身的非人类主体,不能在日志里伪装成某位员工。

7. 短期身份仍需要主动撤销与运行状态检查

有效期只给出了过期上限。若用户被禁用,而网关只检查一个剩余五分钟有效期的凭证,调用仍可能继续;若旧 TLS 连接被复用,更新证书也未必中止已建立的连接。

一种可复验的撤销流程是:IdP 禁用事件更新用户状态;绑定失效;任务与实例被标记停止;身份签发与续期停止;网关拒绝新的凭证取用与调用;刷新令牌和仍可用的连接撤销;运行中的任务与重试队列中止。必要时关闭现有连接,或在每个请求上检查运行状态。下游支持何种撤销方式也应单独登记。

CREATED → ACTIVE → STOPPING → REVOKED → DESTROYED
             │
             └─ 到期 / 用户停用 / Agent 停用 / 会话结束

状态转换必须阻止“停用后续期”和“被停止的任务因重试重新激活”。状态缓存要有上限;事件丢失时有补偿同步;高风险调用无法确定当前状态时应拒绝。V1.4.4 要求会话结束或实例销毁立即吊销对应身份,V10.4.1 则要求用户禁用或降权后的调用在约定窗口内被拒。两个控制不能被混成“等 JWT 自然过期”。

测量撤销时,在禁用前开始对各网关节点与连接器持续探测,记录禁用事件、最后一次成功,以及之后首次持续拒绝的时间。最后成功只给出下界,稀疏探测可能低估延迟;报告观测区间、采样间隔与缓存配置,并以连续拒绝且没有后续成功验证约定上限。没有禁用后的成功样本时,也不能直接宣称零延迟。撤销不会回滚已经送达下游的操作,已提交的外部效果需要独立追踪和处置。

8. 用八个实验验收身份链

实验 预期结果 主要条款
修改渠道显示名或邮箱 企业主体与权限不改变 V1.2.2
用另一租户的账号完成绑定事务 拒绝绑定,不产生关联记录 V1.2、V1.5.2
重放事件、已消费事务,或转交有效绑定链接 不重复创建;受害人不得在未确认固定目标账号的情况下绑定到攻击者账号 参考流程的防重放与绑定意图控制
修改请求中的用户、Agent、实例字段 不能覆盖工作负载认证主体 V1.4.3
让实例 B 使用实例 A 的证明 凭证持有边界或实例绑定阻止借用 V1.4.1;结合执行隔离验收
发送错受众、过期或未可信签发的证明 网关认证拒绝,无下游凭证取用 V1.4、V4.6.3
停止会话后重放旧证明、复用旧连接 调用被拒,停止状态不会被续期覆盖 V1.4.4
禁用用户后运行定时任务或旧队列 在约定窗口内阻断,留下可关联记录 V2.3.2、V10.4

保留认证事件、绑定版本、实例登记、拒绝原因、停用时间和下游日志。日志中不要保存原始令牌或私钥;令牌标识、证书指纹与受限的主体标识通常足以做关联。对于 JWT bearer 方案,凭证被窃取后可能被重放;若声称实例绑定能抵抗这类攻击,必须提供持有证明、密钥保护或等价机制的验证证据,不能只依赖载荷里的实例名称。

身份链验证完成之后,仍需要判断这个主体是否可以对这份资源做这项操作。继续阅读授权与执行篇,或回看威胁建模与评估篇。完整基线与自评工具由 Teloa AI Security维护,源于 Teloa 的开发实践。