50
50 / 50

Claude Code 沙箱安全机制:双层隔离

⏱️ 25分钟

“少弹权限框”不是安全目标,限制 blast radius 才是。Claude Code 沙箱用文件系统与网络两道边界约束 Bash 及其子进程;权限规则则决定哪些工具可以被尝试。两层要一起使用。


沙箱到底拦什么

Claude 决定调用 Bash
  ↓ 权限规则:这类命令允许尝试吗?
Sandboxed Bash
  ├─ 文件系统:可读/可写路径
  └─ 网络代理:允许/拒绝域名
  ↓
命令及所有子进程继承相同边界
控制面作用范围典型配置
PermissionsBash、Read、Edit、WebFetch、MCP 等工具allow / ask / deny
Filesystem sandboxBash 和子进程allowWrite、denyRead、denyWrite
Network sandboxBash 和子进程的出站连接allowedDomains、deniedDomains
Container/VM整个进程与操作系统视图用户、挂载、namespace、seccomp

沙箱只覆盖 Bash 命令及子进程,不能自动约束所有 MCP server,也不能替代容器、最小权限凭证或代码审查。


平台实现

  • macOS 使用 Seatbelt。
  • Linux 与 WSL2 使用 bubblewrap;网络代理还需要 socat
  • WSL1 不支持所需的内核隔离能力。
  • Linux/WSL2 中的沙箱会阻止通过 Unix socket 启动 Windows 二进制。

Ubuntu/Debian 安装依赖:

sudo apt-get install bubblewrap socat

然后在 Claude Code 中运行 /sandbox,选择 auto-allow 或 regular permissions。两种模式的隔离强度相同,区别只是沙箱内命令是否自动批准。


一份保守的项目配置

放在项目的 .claude/settings.json

{
	"permissions": {
		"deny": ["Read(./.env)", "Read(./secrets/**)", "Bash(git push *)"]
	},
	"sandbox": {
		"enabled": true,
		"failIfUnavailable": true,
		"autoAllowBashIfSandboxed": true,
		"allowUnsandboxedCommands": false,
		"filesystem": {
			"denyRead": ["~/"],
			"allowRead": ["."],
			"denyWrite": ["/etc", "/usr/local/bin"],
			"allowWrite": ["/tmp/project-build"]
		},
		"network": {
			"allowedDomains": ["registry.npmjs.org", "api.anthropic.com"],
			"deniedDomains": ["metadata.google.internal"]
		}
	}
}

failIfUnavailable: true 很重要:如果组织把 sandbox 当安全闸门,依赖缺失时应该启动失败,而不是警告后无沙箱运行。


路径规则最容易配错

Sandbox filesystem 使用常规路径语义:

写法含义
/tmp/build文件系统绝对路径
~/cache用户主目录下路径
./output项目设置中相对项目根目录
.当前设置作用域的根目录

如果项目设置先 denyRead: ["~/"],再 allowRead: ["."],就能实现“默认不读 home,只重新放行当前项目”。如果同一配置写在用户级设置,. 会解析到 ~/.claude,不是任意项目目录。


网络白名单不是内容审计

内置代理根据目标 hostname 做允许判断,不终止 TLS,也不检查加密内容。因此:

  • 放行 github.com 仍可能提供数据外泄通道。
  • *.example.com 的 blast radius 大于单个 API host。
  • 强威胁模型应使用自建代理终止 TLS、记录请求并检查内容。
  • 不要允许 Docker socket;它等价于给沙箱访问宿主机的通道。

网络策略设计顺序:先列任务所需 endpoint,再逐个放行;不要从“允许互联网”开始做黑名单。


凭证边界

沙箱不是秘密管理器。项目应做到:

  1. 用短时 token,不把长期密钥写进仓库。
  2. 用权限规则和 denyRead 隔离 .env、SSH、云凭证。
  3. 为不同工具发最小权限身份。
  4. 通过外部代理或 broker 注入凭证,Agent 不直接看到真值。
  5. 审计每次外部写操作的身份、目标和 provider receipt。

如果命令必须访问 ~/.kube,优先精确加入 filesystem.allowWrite;不要把整个 kubectl 排除出沙箱。


excludedCommands 和逃生口

Docker、watchman 或某些系统工具可能无法在沙箱内工作。excludedCommands 会让匹配命令直接在沙箱外运行,风险应被明确记录。

allowUnsandboxedCommands: false 会关闭 dangerouslyDisableSandbox 逃生口。企业策略通常还要:

  • 管理设置强制 sandbox enabled。
  • 禁止 bypass permissions mode。
  • 只接受 managed domain allowlist。
  • 固定 MCP server allowlist。

验证,不要只看配置文件

测试预期结果
在项目内创建临时文件成功
/usr/local/bin被拒绝
读取被禁的 .env被拒绝
请求允许域名成功
请求随机域名被拒绝或触发权限流程
子进程尝试相同越界行为同样被拒绝
移除 bubblewrap 后启动(强制模式)启动失败

把这些测试加入团队 onboarding 或 CI 环境镜像验收。配置存在,不等于实际运行时启用了隔离。


常见错误

错误后果修法
只配 permissions,不开 sandbox恶意子脚本绕过意图判断加 OS 级运行时边界
只限制文件,不限制网络读取到的数据可被外传两层同时启用
放行过宽 wildcard白名单变成外泄跳板精确到必要 host
允许 Docker socket可控制宿主机禁止 socket,另建隔离 runner
沙箱不可用时继续运行生产策略静默失效failIfUnavailable: true

动手练习

为一个 Node.js 项目写 sandbox policy:只允许项目目录和 /tmp/build 写入,只允许 npm registry 与测试 API 出站。然后用主进程和 npm 子脚本分别尝试越界读、写、联网,保存实际拒绝结果。

自检

  • 我能解释 permissions 与 sandbox 的不同执行时机。
  • 文件系统和网络隔离都已启用。
  • 凭证不直接暴露给生成代码。
  • 沙箱不可用会 fail closed。
  • 我测试了子进程,而不只测试 Claude 的直接命令。

相关阅读

参考资料

📚 相关资源

常见问题

点击问题,查看本章对应的实践答案。

沙箱和权限规则(permission rules)有什么区别?

权限规则在命令运行前根据命令字符串判断,防不住 npm install 里 postinstall 脚本干坏事;沙箱由操作系统(macOS Seatbelt / Linux bubblewrap)在运行时拦截进程本身,命令 spawn 的所有子进程都逃不出文件和网络边界。两者互补,不是替代关系。

开了沙箱是不是就不用管凭证安全了?

不是。默认读策略下 ~/.ssh/ 和 ~/.aws/credentials 仍然可读,环境变量也会原样继承给沙箱内命令。必须自己配 sandbox.credentials(deny 直接封禁,mask 用哨兵值替换、代理出站时注入真值)或设 CLAUDE_CODE_SUBPROCESS_ENV_SCRUB 才算保护到位。

Windows 上能用 Claude Code 沙箱吗?

原生 Windows 和 WSL1 都不支持。必须在 WSL2 里运行 Claude Code,并安装 bubblewrap 和 socat 两个依赖(sudo apt-get install bubblewrap socat);注意 WSL2 沙箱内无法调用 cmd.exe 等 Windows 二进制,需要的话加进 excludedCommands。

沙箱能完全防住数据外泄吗?

不能。内置代理默认只看目标域名、不解密 TLS 流量,放行 github.com 这类大域名后仍可能被 domain fronting 当外泄跳板。官方建议:威胁模型要求强保证时配自建代理做 TLS 终止 + 内容审计,白名单只放真正信任的域名。