沙箱、权限、审批与回滚
本节目标
- 把 capability、identity、policy、approval 与 sandbox 分成独立控制层。
- 根据副作用而非工具名称给动作分级。
- 为不可逆操作定义停止、审批、回滚或补偿策略。
为什么“模型会谨慎”不是安全控制
环境型 Agent 同时处理用户指令和不可信网页、文档、issue、终端输出。模型可能误解、受提示注入影响或在状态变化后继续旧计划。只在 prompt 中写“不要删除文件”无法阻止拥有删除权限的 adapter;沙箱也不能替代业务授权,因为隔离环境内仍可能向真实 API 发消息或下单。
控制必须在模型之外组合:identity 决定“是谁”,capability 描述“能请求什么”,policy 决定“此上下文能否做”,approval 处理需要人承担的具体决策,sandbox 限制执行爆炸半径,receipt/audit 记录实际发生了什么。
身份、委派、凭据与审批是四份不同证据
| 证据 | 谁签发或验证 | 应绑定的内容 | 典型错误 |
|---|---|---|---|
| subject identity | 身份提供者、受信 session 或服务身份 | 用户/服务主体、租户、认证强度、会话或服务 ID | 把模型声称的用户名、页面头像当身份 |
| delegation / capability | policy service 或 runtime | purpose、工具/资源 scope、预算、expiry、run | 给 Agent 人类管理员的长期全局 token |
| adapter credential | 凭据服务与 adapter | 仅本次环境、最小作用域、短生命周期和可撤销性 | 用“用户已登录”推断任何站点或系统都能操作 |
| approval | 受信审批者或工作流 | 一个规范化的高影响 intent、目标、金额/数据范围、当前环境和 nonce | 把“允许继续”或模型输出当通用批准 |
运行记录应把 subject、delegation、adapter actor、policy decision、approval 与 receipt 的可验证、受完整性保护的关联记录下来,供后续对账;但审计不是把完整 prompt、网页、文件、token 和 PII 无限期复制到日志。为每个字段定义分类、最小留存期、受保护原文位置、hash/digest、脱敏规则和查看者权限。高影响操作若无法写入必要的安全审计证据,应按风险选择失败关闭或转人工,而不是静默继续。
怎样实现
| 风险级别 | 示例 | 默认控制 |
|---|---|---|
| 只读、低敏感 | 读取允许目录、查询测试状态 | scope allowlist、速率/预算、审计 |
| 可逆本地写 | 在隔离 worktree 编辑文件 | snapshot/diff、幂等、路径限制、自动回滚 |
| 外部可补偿写 | 创建草稿、建立可取消预约 | 精确 identity、预览、幂等、补偿步骤、必要审批 |
| 不可逆或高影响 | 付款、发送、删除、发布、改权限 | 默认拒绝;强身份、短期精确审批、双人或人工执行 |
批准对象应包含:task/run/policy、action ID、动作类型与规范化参数摘要、幂等键、目标身份/路径/origin、金额或数据范围、环境实例 ID、state fingerprint/generation、过期时间、批准人和一次性 nonce。任一关键字段变化都使批准失效;只有版本号相同并不足以证明环境仍是批准时的状态。
批准记录不能成为模型动作 schema 的可选字段。课程 runtime 的 Action.from_dict 对未知字段失败关闭;批准由模型之外的 register_approval 控制面接收,并用受信批准者的 HMAC 密钥验签。签名 payload 明确绑定 task_id、run_id、policy_version、action_id、idempotency_key、intent_digest、environment_version、environment_instance_id、state_fingerprint、environment_generation、expires_at_proposal、expires_at_unix_ms 与 nonce。proposal 计数 expiry 限制最多可到哪个 proposal(相等时仍有效),可信墙钟 expiry 则避免 Agent 停止提议时批准永久有效(到期时刻即失效)。runtime 在动作真正通过授权门时消费 nonce;若写动作进入 pending,则把完整签名证据和已消费集合写入经过认证的 checkpoint。恢复会重新验签、检查信任根和状态绑定,但不会把过期历史证据误判为 checkpoint 损坏:pending 仍被执行门冻结,只有 refresh_pending_approval 收到 fresh、同 action/key/intent/instance/fingerprint/generation 的可信签名后才能替换 active evidence,旧证据保留在 trace。未知签发者、签名篡改、跨 task/run/policy/action/幂等键重放、同版本但不同状态、过期自动执行,以及试图从幂等 replay 绕过审批都失败关闭。
教学 HMAC 的边界
对称 HMAC 只用于演示“签发权不属于模型进程”的可信边界;生产系统通常应使用独立审批服务、KMS/HSM 或可验证的非对称签名,并把签发、注册、消费、撤销和密钥轮换纳入审计。若模型能读取批准密钥,所有字段绑定都会失去意义。
回滚要按环境区分:浏览器草稿可删除或撤销,桌面文件可从 snapshot 恢复,代码可反向应用精确 patch。外部消息、付款或数据披露通常不能真正回滚,只能补偿或事故响应,因此应在执行前提高审批和预览强度。
常见失败
- 给 Agent 使用人类管理员账号,所有 tool 共享同一长期 token。
- approval 只写“允许继续”,或让模型把 approval 字段与动作一起生成;目标、金额或内容改变后仍有效。
- sandbox 允许任意网络,隔离文件系统却挡不住数据外泄。
- 把网页/issue/测试输出中的文本提升为授权来源。
- 重试非幂等写动作;回滚脚本反而覆盖用户的新修改。
- 只有成功日志,没有拒绝、批准、取消、接管和恢复审计。
怎样验证
构造越权矩阵:每个身份对每个 action/scope 都测允许与拒绝;拒绝必须发生在副作用之前。分别篡改签名、task/run/policy/action、幂等键、intent、环境实例、状态指纹/generation 和两类 expiry,并验证 nonce 消费后在 checkpoint 恢复前后都不能重放。再构造“版本相同但内容不同”“状态相同但环境实例不同”“等待但不增加 proposal 直至墙钟到期”“过期 pending 恢复后仍不可执行、fresh exact approval 才能解冻”和“已有 receipt 但缺少新审批”的用例。注入间接提示、网络外传、路径穿越、symlink/重定向、重复请求和人工取消,核对结果及环境 diff。对补偿流程进行演练,不能只验证“存在一个撤销按钮”。
实践任务
为“读取工单、生成回复、发送邮件”设计三段能力:读取工单、保存草稿、发送。分别指定身份、数据范围、网络目的地、幂等键和审批。证明恶意工单内容不能改变收件人;批准后的正文或收件人变化会触发重新审批;发送超时后先查 receipt 而非直接重发。
参考
- AI 安全:提示注入、最小权限、供应链、沙箱与事故恢复。
- 人在回路与控制权:approval fingerprint、state version、scope 与 expiry。
- Playwright:Best Practices:隔离测试和避免依赖不可控第三方环境的工程实例。
- OWASP AI Agent Security Cheat Sheet:最小工具权限、外部数据边界、敏感操作和安全测试(访问于 2026-07-22)。
- OWASP MCP Security Cheat Sheet:confused deputy、跨服务权限聚合、工具返回值注入及审计边界(访问于 2026-07-22)。