3.1 allowlist 与审批门在沙箱内的落位


3.1 allowlist 与审批门在沙箱内的落位

本节摘要:权限与审批门的设计原理——为什么默认拒绝、如何分级、审批如何避免训练出「无脑点同意的人」——《Harness 工程:从零打造智能体运行环境》第 5 章已经讲透,本书不重写;本节只管把这些原理装进第 2.3 节的网关。内容有三块:其一,命令规则的三种粒度(精确匹配、子命令匹配、模式匹配)与各自的陷阱——前缀放行 git 等于放行 git 的一切,是最常见的自毁式白名单;其二,路径作用域的落地:绝对路径收敛到工作区、封禁波浪号与点点穿越,并把「参数里像路径的东西」都当路径检查;其三,审批门的落位:deny 与 needs_approval 是两个不同出口,四类高危动作默认进审批,人类回执后继续或终止流程。

学习目标

  • 按三种粒度编写命令规则并避开各自陷阱。
  • 实现路径作用域检查,封死家目录、点点穿越与工作区外绝对路径。
  • 区分 deny 与 needs_approval 两个出口,配好四类高危动作的审批流程。
  • 会为自己的 Agent 写第一版策略文件。

一、命令规则:三种粒度与三个陷阱

策略的强度取决于粒度。三种粒度从粗到细:

粒度 写法示例(fnmatch 模式) 适用 陷阱
精确匹配 pytest、git status 高频只读命令 无(最安全,尽量用)
子命令匹配 git diff *、git log * 某命令的特定子集 子命令仍带参数,注意参数里的路径
模式匹配 python *.py 带参数的常用组合 通配符过宽等于没拦

三个真实陷阱,每个都对应一次可预见的失守:

陷阱一:前缀放行。 允许 git * 看似方便,实际放行了 git push(外发)、git clean -fdx(删库)。正确做法是精确到子命令:git status、git diff *、git log * 各自单列,用不到的子命令不进名单。

陷阱二:模式过宽。 python * 意味着 python -m http.server 也被放行——沙箱断网时它是哑弹,一旦第 4 章讨论的「受控出站」放开,它就是隧道。收紧为 python *.py,再对入口文件名做模式约束。

陷阱三:shell 包装穿透。 只要允许任何能起 shell 的形式(sh -c ...、bash ...、python -c ...),后续所有规则都在字符串内部失效。第 2.3 节拒收 shell 字符串是第一道锁;策略里不列 shell 与 -c 类入口是第二道锁。

💡 写策略的顺序建议:从「完全空白 + deny 兜底」起步,让真实工作流把命令一条条「申请」进名单——自下而上长出来的白名单,比抄来的模板清单贴合得多,也短得多。

二、路径作用域:命令对了,路径错了,照样出事

命令白名单管「做什么」,路径作用域管「对哪里做」。落位实现(可直接并入 gateway.py 的 check 函数):

# policy_paths.py —— 路径作用域检查:一切像路径的参数都必须收敛在工作区内(示意实现) def path_scope_ok(argv: list) -> tuple: for a in argv[1:]: if a.startswith("~"): return False, f"封禁家目录引用: {a}" parts = a.split("/") if ".." in parts: return False, f"封禁点点穿越: {a}" if a.startswith("/") and not (a == "/workspace" or a.startswith("/workspace/")): return False, f"绝对路径越界: {a}" return True, "ok" ​

三条规则各有对手:~ 展开直取家目录的 .ssh、.aws;.. 穿越(/workspace/../etc/passwd)绕过前缀判断;工作区外绝对路径直接打击 /etc、/var。加上第 2.1 节的只读根,这里形成双保险:策略层挡「明显越界」,文件系统层挡「漏网的写」。

⚠️ 已知局限:这套检查是文本级的,不解析引号内的语义,也不追符号链接(symlink 可能指向工作区外)。生产化应在沙箱内做真实路径解析(realpath 归一后再判前缀),文本级检查当作第一道滤网——示意实现与生产实现的差距,正在于这类边角。

三、审批门落位:deny 与 needs_approval 是两个出口

策略评估不该只有「行 / 不行」两态。三个出口各司其职:

(文字流程图)网关决策的三出口 命令 ──▶ deny 规则命中 ─────────────▶ 出口一 deny:直接拒绝并落审计 ──▶ allow 命中且路径合规 ─────────▶ 出口二 allow:进沙箱执行 ──▶ 未命中任何名单(灰区)────────▶ 出口三 needs_approval:挂起,等人 │ 人批准 ──▶ 进沙箱执行(审计记 reviewer) 人拒绝 ──▶ 记 deny(审计记 reviewer) ​

四类默认进审批的高危动作(抄走即用):

类别 触发示例(示意) 为什么不能自动
工作区外写 路径不在 /workspace 内的写操作 破坏范围不可控
网络出站 curl、pip install(联网下载) 数据外传与供应链入口
删除与覆盖 rm、git push --force 不可逆
安装与执行新代码 pip install <包名>、运行下载来的脚本 供应链投毒入口(第 4 章主题)

审批门的落位要点:回执里必须带完整命令与完整参数让人看——恶意 Skill 事件(CVE-2026-100602,官方记录)的问题恰恰出在审批流程缺失「预览」环节,人在没看清将执行什么的情况下点了同意;此外同一命令短时间重复触发审批要合并提示,否则人会被训练成条件反射式同意。这两个「人的因素」的原理展开见《Harness 工程:从零打造智能体运行环境》第 5 章。

四、动手:写下第一版策略

# policy.py —— 第一版策略文件:精确优先、deny 兜底、灰区进审批(示意,按项目裁剪) ALLOW = [ "ls", "ls *", "cat *", # 只读浏览 "git status", "git diff", "git diff *", "git log", "git log *", # 精确到子命令 "python *.py", "pytest", "pytest -q", "pytest tests/*", # 受限执行 "pip install -r requirements.txt", # 锁定文件式安装(内容治理见第 4 章) ] DENY = [ "*curl*", "*wget*", "*nc *", "*ssh*", # 网络工具 "*sudo*", "*chmod*", "*chown*", # 提权与改权 "rm *", "* > /dev/*", "*mkfs*", "*dd if=*", # 破坏性 "git push*", # 外发 ] APPROVAL_HINTS = ["pip install", "rm", "git push", "curl", "wget"] # 灰区优先提示 ​

验证方法照抄第 2.3 节冒烟测试:每类各放一条命令,期望分别命中 allow、deny、路径越界三个分支。

本节要点回顾

  • 三种粒度各有陷阱:前缀放行、模式过宽、shell 包装穿透;策略自下而上生长,不要抄模板。
  • 路径作用域三规则:封波浪号、封点点穿越、绝对路径收敛工作区;文本级是第一道滤网,生产要做 realpath 归一。
  • 三出口:deny(拒绝)、allow(执行)、needs_approval(挂起等人);回执必须完整展示命令——CVE-2026-100602 的教训正是缺了「预览」。
  • 第一版策略文件即拿即改,验证方法复用第 2.3 节冒烟测试。

策略挡在事前,但「deny 了多少次、批了多少次、deny 的都是什么」同样是金矿——这需要把每个决策点变成结构化、防篡改、可回放的记录。下一节补上最后一块拼图:审计日志与回放。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U