ADR-0004:安全管控插件层的定位——进程内策略执行层,不是安全边界
- 状态:已采纳
- 日期:2026-09-15
- 决策者:毕设作者
- 相关文档:
docs/02-安全管控插件层设计.md、docs/adr/0002-mcp-gateway-as-sole-egress.md、docs/adr/0003-openclaw-as-agent-core.md
背景
本课题的主要实现部分是"安全管控插件层"。一个必须提前回答、且答辩时几乎必被追问的问题是:
这一层到底是不是安全边界?如果是,它能防住什么?
OpenClaw 官方文档给出了明确答案:插件与 Gateway 在同一进程中运行,应被视为可信代码;同时 OpenClaw 的整体信任模型是"单用户个人助理",明确不把同一 Gateway 内的多个用户视为互相敌对的租户。
如果我们把"防止 Agent 越权"的全部责任压在这一层上,就是在一个框架明确声明"我不做多租户隔离"的地方宣称自己做了隔离——这在答辩上是站不住的。
决策
明确区分两个层次,并在所有文档中保持一致措辞:
| 层 | 名称 | 部署形态 | 性质 | 能防住什么 |
|---|---|---|---|---|
| L1 | 安全管控插件层 | OpenClaw 进程内的原生插件 | 策略执行层(policy enforcement,非硬边界) | 拦截工具调用、参数校验与改写、字段脱敏、审计上报、行为约束与配额、提示词塑形 |
| L2 | MCP 安全网关 | 独立进程,独立凭证,独立部署单元 | 安全边界(hard boundary) | Agent 无凭证 ⇒ 物理上不可达;字段白名单裁剪;策略判定;审计落库 |
纵深防御的表述方式:L1 让"不合规的调用在发起前就被拦下",L2 让"即使 L1 被绕过,Agent 也拿不到它不该拿的数据"。
同时明确 L1 不承诺以下能力(写进文档、答辩时主动说明):
- 不承诺抵御恶意插件代码(同进程 ⇒ 恶意插件可绕过钩子直接调用内部 API);
- 不承诺多用户之间的隔离(框架不支持);
- 不承诺在 Agent 进程被完全攻陷时仍有效(进程内策略层随宿主一起失守)。
理由
- 诚实的技术论证比夸大更得分。答辩评委常见追问是"你这一层能不能被绕过"。主动区分硬边界与策略层,并给出绕过路径与兜底手段,比声称"绝对安全"更有说服力。
- 两层职责互补,不重复。L1 的优势是上下文完整——它能看到完整的会话、模型提示词、工具参数与 Skill 调用链,因此能做"语义级"判定(例如"这次调用与当前任务无关")。L2 的优势是权限最小——它拿不到会话上下文,但持有唯一的数据凭证。两者不可互相替代。
- 符合纵深防御(defense in depth)的常规做法。工业系统里"进程内策略 + 进程外网关"是标准组合,不是本课题的发明。
备选方案与拒绝理由
| 方案 | 为什么没选 |
|---|---|
| 只做 L1(插件层),不建独立网关 | 插件层无法提供凭证隔离,"Agent 拿不到业务库账号"这一最强论证不成立;也无法做字段级裁剪。 |
| 只做 L2(网关),不做插件层 | 网关看不到会话上下文,无法判断"调用是否与当前任务相关";也无法在提示词层面塑形、无法对 Skill 调用做配额约束。而且课题要求的"主要实现部分"就没了。 |
| 把 L1 做成独立代理进程(拦在 Agent 与网关之间) | 逻辑上更干净,但会引入第三个网络跳转与新的单点,且"插件层"的课题表述落空。原型阶段不值得。 |
后果
正面
- 安全论证分为"策略层拦住了什么"与"边界层兜住了什么"两条独立证据链,答辩时可用两组实验分别演示。
- 与 OpenClaw 官方信任模型不冲突,不会被评委用官方文档反驳。
- 插件层的定位清晰后,实现范围收敛:只做"钩子拦截 + 策略引擎 + 审计上报",不试图做凭证管理。
负面 / 代价
- 需要额外实现并守护一个独立网关进程(PM2 配置、健康检查、降级策略)。
- 文档与答辩材料中必须反复强调两者的区别,否则容易被误解为"两层做同一件事"。
相关设计约束
- L1 的所有策略判定结果都必须上报网关并落审计,不允许只在插件内留日志。审计的唯一权威落点是
business-db.audit_log。 - L1 的策略失败必须 fail-closed(拒绝调用),不允许 fail-open。
- L1 不得持有
business-db或ai-db的任何连接串——它只调用网关的 HTTP/MCP 接口。