第 14 章:权限与安全
在第 9 章中,我们学习了五种权限模式(Ask / Edit / Plan / Auto / Bypass)——它们控制的是 Claude Code 是否向你确认。但权限模式只是安全体系的第一层。当你把规则从"每步都问"升级到"自动执行"时,真正保护你代码安全的是背后的 allow / deny 规则系统。
本章深入 Claude Code 的权限架构:规则如何匹配、deny 为什么永远优先、如何为不同环境设计合适的权限策略。这是进阶篇的最后一章,也是从"会用 Claude Code"通向"安全地用 Claude Code"的关键桥梁。
本章目标:理解权限系统的完整架构,掌握 allow / deny 规则的语法和优先级,能根据项目类型和环境设计安全的权限配置。
14.1 权限系统架构
Claude Code 的权限系统是一个多层过滤架构。每次工具调用都要经过层层检查,最终产生三种结果之一。
权限检查流程
这个流程有几个关键点值得注意:
- deny 是绝对优先的:即使 Bypass 模式下,deny 规则仍然生效。你不可能通过切换模式来绕过 deny 规则。这是一个刻意的安全设计。
- allow 规则让你跳过确认:在没有 Bypass 的情况下,allow 规则作用的对象不再弹出确认窗口,直接执行。这是"效率优先"的实现方式。
- 没有规则匹配时,走默认风险评估:Claude Code 对每种工具调用有内置的风险评级,在没有显式规则覆盖时生效。
三种权限结果
| 结果 | 含义 | 触发条件 |
|---|---|---|
| 🟢 Auto-allow | 直接执行,不询问 | Bypass 模式下的非 deny 操作;或 allow 规则明确匹配 |
| 🟡 Ask user | 弹出确认窗口,等待用户决定 | 非 Bypass 模式下,操作不在 allow 列表中,且风险等级不高 |
| 🔴 Auto-deny | 直接拒绝,不询问 | deny 规则匹配(任何模式下均生效) |
基于风险的内置默认行为
即使你完全没有配置任何权限规则,Claude Code 也有内置的风险评估:
| 风险等级 | 典型操作 | 默认行为 |
|---|---|---|
| Level 1:低风险 | Read 文件、Bash(ls:*)、Bash(git:status)、搜索代码 | 自动允许(只读、无副作用) |
| Level 2:中风险 | Write 文件、Edit 文件、Bash(pnpm:*)、Bash(git:commit) | 按需确认(有副作用但可控) |
| Level 3:高风险 | Bash(rm:*)、Bash(sudo:*)、Bash(git:push:--force) | 始终确认(不可逆或影响范围大) |
这个内置分级是 Claude Code 的安全底线——即使你没有任何自定义规则,它的默认行为也不会让灾难性操作静默通过。
VSCode 中的权限弹窗
在 VSCode 扩展中,当一个操作需要你确认时,侧边栏会弹出权限确认对话框。对话框包含以下信息:
- 操作类型:Write / Edit / Bash(具体命令)
- 目标文件:操作影响哪些文件,完整路径
- 变更内容:修改前后的代码对比(对于 Edit/Write)
- 三个选项:
- Allow:批准本次操作,Claude 继续执行
- Deny:拒绝本次操作,Claude 调整方案或停止
- Allow All:本次对话后续同类型操作不再询问(临时 allow,不会写入配置)
理解了这个流程架构,下一步就是学习如何通过 allow / deny 规则来精确控制这一切。
14.2 allow / deny 规则语法
权限规则定义在 settings.json 的 permissions.allow 和 permissions.deny 数组中。每一条规则是一个字符串,描述了匹配哪些工具调用。
规则格式
规则的基本格式为 工具名称(参数模式):
工具名称(参数1:参数2:...)工具名称支持 Claude Code 的所有核心工具:Read、Write、Edit、Bash、WebSearch、WebFetch、TodoWrite、TaskOutput 等。其中 Bash 是最常用也最需要精细控制的工具——因为它能执行任意 Shell 命令。
匹配模式详解
精确匹配
匹配一个完全确定的命令,不包含任何通配符:
{
"allow": [
"Bash(git:status)",
"Bash(git:diff)",
"Bash(git:log)",
"Bash(pnpm:install)",
"Bash(node:--version)"
]
}Bash(git:status) 只匹配 git status,不匹配 git status --short 或 git stash。精确匹配适合你完全信任且频繁使用的特定命令。
通配符匹配
用 * 匹配任意参数:
{
"allow": [
"Bash(git:*)", // 匹配所有 git 命令
"Bash(pnpm:*)", // 匹配所有 pnpm 命令
"Bash(npm:*)", // 匹配所有 npm 命令
"Bash(ls:*)", // 匹配 ls 的所有变体
"Bash(cat:*)" // 匹配 cat 的所有调用
]
}Bash(git:*) 匹配 git status、git diff、git commit、git push 等一切以 git 开头的命令。这是最常用的匹配模式——你信任某个工具链(如 git、pnpm),但不限制具体子命令。
深层参数匹配
* 可以出现在命令的任意位置,匹配一部分参数:
{
"allow": [
"Bash(git:push:*)", // 匹配所有 git push,不管推到哪里
"Bash(docker:compose:*)", // 匹配所有 docker compose 子命令
"Bash(npm:run:*)", // 匹配所有 npm run 脚本
"Bash(cargo:build:*)", // 匹配 cargo build 的所有选项
"Bash(ssh:*)", // 匹配所有 SSH 连接
"Bash(curl:*)", // 匹配所有 curl 请求
"Bash(git:remote:*)" // 匹配所有 git remote 操作
]
}危险模式匹配
用精确的深层匹配来拦截特定危险模式:
{
"deny": [
"Bash(rm:-rf:*)", // 递归强制删除任何内容
"Bash(rm:-r:*)", // 递归删除(即使没有 -f)
"Bash(sudo:*)", // 任何 sudo 提权操作
"Bash(git:push:--force:*)", // 强制推送
"Bash(git:push:-f:*)", // -f 简写形式
"Bash(git:reset:--hard:*)", // 硬重置
"Bash(chmod:777:*)", // 危险的权限修改
"Bash(chown:*)", // 改变文件所有者
"Bash(curl:*:* |*:bash)", // curl 结果管道到 bash(远程代码执行)
"Bash(wget:*:* |*:bash)" // wget 同理
]
}⚠️ 注意:
Bash(rm:-rf:*)匹配的是rm -rf something,冒号对应空格。如果命令中有管道或重定向符号(|、>、>>),这些字符在规则中也按字面匹配。
无参数工具规则
对于不需要参数的工具(如 WebSearch、WebFetch),规则只写工具名称:
{
"allow": [
"WebSearch", // 允许所有 Web 搜索
"WebFetch" // 允许所有 Web 抓取
],
"deny": []
}对于 Read、Write、Edit,规则中可以包含文件路径模式:
{
"allow": [
"Read(*)", // 允许读取任何文件
"Write(src/**)", // 允许写入 src/ 下的任何文件
"Edit(src/**)" // 允许编辑 src/ 下的任何文件
],
"deny": [
"Write(.env)", // 禁止写入 .env 文件
"Write(**/*.secret.*)", // 禁止写入任何 .secret.* 文件
"Read(**/*.pem)" // 禁止读取私钥文件
]
}规则优先级:deny 永远胜出
权限系统的核心原则只有一条:
deny 永远优先于 allow。与规则的书写顺序无关。
{
"allow": [
"Bash(git:*)", // 允许所有 git 命令
"Bash(git:push:--force:*)" // 试图允许 force push
],
"deny": [
"Bash(git:push:--force:*)" // 禁止 force push
]
}在这个配置中,即使 allow 列表中包含 Bash(git:push:--force:*),deny 列表中的同名规则仍然会阻止它。deny 的优先级不依赖于书写顺序——它总是胜出。
这个设计的含义是:你可以在 allow 中使用宽松的通配符(如 Bash(git:*)),然后用 deny 精确地"挖掉"你不想要的子集。这是一种安全且高效的做法——先开门,再锁上不该开的窗户。
规则评估逻辑(伪代码)
def check_permission(tool_call, allow_rules, deny_rules):
# 第一步:检查 deny(永远先检查)
for rule in deny_rules:
if matches(tool_call, rule):
return "DENY" # 直接拒绝,不再往下走
# 第二步:检查 allow
for rule in allow_rules:
if matches(tool_call, rule):
return "ALLOW" # 匹配到就放行
# 第三步:没有匹配,走默认风险评估
return default_risk_assessment(tool_call)理解这个逻辑后,配置策略就很清晰了:allow 写你信任的,deny 挖掉你担心的。
14.3 权限规则实战
理解了语法和优先级后,让我们从简单到复杂,逐步构建实际可用的权限配置。
基础配置:允许读,禁止危险操作
这是最低限度的配置——只让 Claude 做只读操作,一切有副作用的操作都需要确认:
{
"permissions": {
"allow": [
"Bash(git:status)",
"Bash(git:diff)",
"Bash(git:log)",
"Bash(ls:*)",
"Bash(cat:*)",
"Bash(head:*)",
"Bash(tail:*)",
"Bash(wc:*)",
"Bash(find:* .)",
"Bash(grep:* *)"
],
"deny": [
"Bash(rm:*)",
"Bash(sudo:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(chmod:*)",
"Bash(chown:*)"
]
}
}适用场景:刚接触 Claude Code 的前几周;在陌生项目中探索代码时;需要 Claude 帮你分析代码但不希望它动手修改。
局限性:你每次让 Claude "改一下这个函数"时,它都会弹出确认窗口。如果一天有 30 次这样的操作,你会很快感到打断频繁。
进阶配置:允许特定工具链
当你对 Claude 的行为建立了信任,可以扩大到允许日常开发工具链的自动执行:
{
"permissions": {
"allow": [
"Bash(pnpm:*)",
"Bash(npm:*)",
"Bash(node:*)",
"Bash(git:status)",
"Bash(git:diff)",
"Bash(git:log)",
"Bash(git:add:*)",
"Bash(git:commit:*)",
"Bash(ls:*)",
"Bash(cat:*)",
"WebSearch",
"WebFetch"
],
"deny": [
"Bash(rm:-rf:*)",
"Bash(sudo:*)",
"Bash(git:push:--force:*)",
"Bash(curl:*)",
"Bash(wget:*)"
]
}
}关键变化:
Bash(pnpm:*)/Bash(npm:*)覆盖了包管理器的所有操作,Claude 可以自主安装依赖、运行脚本Bash(git:add:*)/Bash(git:commit:*)允许 AI 帮你暂存和提交- 但
git push --force仍然在 deny 中,被明确阻止
注意:Bash(git:add:*) 匹配 git add src/file.ts 也匹配 git add -A。如果你只想允许单个文件添加,用更精确的规则;如果你信任 Claude 的判断,通配符覆盖更广。
高级配置:精细控制每一个工具链
当项目有明确的安全边界时,你可以对每个工具链进行精细的拆解:
{
"permissions": {
"allow": [
// Git:允许查看和常规提交,禁止破坏性操作
"Bash(git:status)",
"Bash(git:diff)",
"Bash(git:log)",
"Bash(git:add:*)",
"Bash(git:commit:*)",
"Bash(git:branch:*)",
"Bash(git:checkout:*)",
"Bash(git:stash:*)",
// 包管理:允许完整工具链
"Bash(pnpm:*)",
"Bash(node:*)",
// 文件查看
"Bash(ls:*)",
"Bash(cat:*)",
"Bash(find:* .)",
// 构建与测试
"Bash(pnpm:run:build)",
"Bash(pnpm:run:test:*)",
"Bash(pnpm:run:lint:*)",
"Bash(pnpm:run:typecheck)",
// 网络工具
"WebSearch",
"WebFetch"
],
"deny": [
// 文件删除与权限修改
"Bash(rm:-rf:*)",
"Bash(rm:-r:*)",
"Bash(rmdir:*)",
"Bash(sudo:*)",
"Bash(chmod:*)",
"Bash(chown:*)",
// Git 破坏性操作
"Bash(git:push:--force:*)",
"Bash(git:push:-f:*)",
"Bash(git:reset:--hard:*)",
"Bash(git:clean:*)",
// 未受控的网络请求
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(nc:*)"
]
}
}设计思路:allow 中 Git 的子命令被逐项列出,而不是用 Bash(git:*) 一把梭。这意味着如果 Claude 试图执行 git push(不在 allow 中),它会弹出确认窗口——但 git push --force(在 deny 中)会被直接拒绝。这种"白名单为主、黑名单兜底"的策略在安全性和效率之间取得了很好的平衡。
配置策略对比
| 策略 | Allow 风格 | 优点 | 缺点 | 适用 |
|---|---|---|---|---|
| 宽松 allow | Bash(git:*) 一把梭 | 配置简洁,少写规则 | deny 必须精确,遗漏风险 | 信任度高的小项目 |
| 精细 allow | 逐子命令列出 | 安全边界清晰,意外行为也会被捕获 | 配置长,维护成本高 | 多人协作、敏感项目 |
| 混合策略 | 信任的用通配符,存疑的用精确匹配 | 平衡效率和安全性 | 需要判断哪些该宽松 | 推荐:大多数项目 |
14.4 常见权限配置模板
根据环境的不同,权限配置的策略应该有所区别。以下是三种典型场景的配置模板。
个人开发环境
这是最宽松的配置,适合个人项目、本地实验、学习练习。核心原则:信任工具链,只拦截真正的破坏性操作。
{
"permissions": {
"allow": [
"Bash(git:*)",
"Bash(pnpm:*)",
"Bash(npm:*)",
"Bash(node:*)",
"Bash(ls:*)",
"Bash(cat:*)",
"Bash(mkdir:*)",
"Bash(touch:*)",
"Bash(cp:*)",
"Bash(mv:*)",
"WebSearch",
"WebFetch"
],
"deny": [
"Bash(rm:-rf:*)",
"Bash(sudo:*)",
"Bash(git:push:--force:*)",
"Bash(curl:*:* |*:bash)",
"Bash(wget:*:* |*:bash)"
]
}
}配置说明:
Bash(git:*)全部放行——个人项目中,Git 操作即使错了也可以git reflog找回mkdir/touch/cp/mv放行——这些是日常操作,频繁确认会严重影响效率- deny 专注于两个点:数据不可恢复的删除(
rm -rf)和代码注入风险(curl/wget 管道到 bash)
团队开发环境
在多人协作的项目中,安全性要求更高。核心变化:收紧写入和网络权限,限制 Git 的破坏性操作。
{
"permissions": {
"allow": [
"Bash(git:status)",
"Bash(git:diff)",
"Bash(git:log)",
"Bash(git:branch:*)",
"Bash(git:stash:*)",
"Bash(pnpm:run:*)",
"Bash(npm:run:*)",
"Bash(ls:*)",
"Bash(cat:*)",
"Bash(find:* .)",
"Bash(grep:* *)",
"WebSearch",
"WebFetch"
],
"deny": [
"Bash(rm:*)",
"Bash(sudo:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(git:push*)",
"Bash(git:commit*)",
"Bash(git:reset:*)",
"Bash(git:clean:*)",
"Bash(chmod:*)",
"Bash(chown:*)"
]
}
}关键差异:
git push*和git commit*被 deny——团队成员应该自己审查和提交代码,AI 的角色是辅助而非代替决策pnpm:run:*放行(只运行已有脚本),但pnpm:*不放行(不允许修改依赖)——防止 AI 意外升级或降级依赖导致的 CI 问题- curl 和 wget 全部禁止——团队环境中不应让 AI 自主发起外部网络请求
CI/CD 环境
CI/CD 环境中,Claude Code 通常以非交互模式运行。权限配置的目标不是减少确认弹窗,而是精确控制它能做什么、不能做什么。
{
"permissions": {
"allow": [
"Bash(*)",
"Write(*)",
"Edit(*)",
"Read(*)"
],
"deny": [
"Bash(rm:-rf:/:*)",
"Bash(sudo:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(ssh:*)",
"Write(**/*.env)",
"Write(**/*secret*)",
"Write(**/*.pem)"
]
}
}配置说明:
- allow 极度宽松(
Bash(*)、Write(*))——CI 环境中不需要人工确认 - deny 是真正的防线:绝对路径删除(
rm -rf /)、sudo 提权、网络外联、敏感文件写入 - CI 环境通常有独立的凭据管理机制(如 GitHub Secrets),额外限制敏感文件写入是双重保险
⚠️ CI 环境的权限配置不能"差不多"。生产环境的 CI 流水线如果被 AI 误操作(如
rm -rf $BUILD_DIR写成了rm -rf /),后果在 deny 规则中被阻断——这就是 deny 作为"最后一道防线"的价值。
14.5 安全沙箱
除了 allow / deny 规则,Claude Code 还有一层底层的安全机制:安全沙箱。沙箱不依赖于你写的规则——它是 Claude Code 运行环境的硬性限制。
文件访问:限制在项目目录内
Claude Code 的工具操作(Read / Write / Edit)默认不能访问项目目录以外的文件。
项目目录: /Users/me/project/
允许读取: /Users/me/project/src/main.ts ✅
允许写入: /Users/me/project/.claude/settings.json ✅
禁止读取: /Users/me/.ssh/id_rsa ❌
禁止写入: /etc/hosts ❌
禁止读取: ../../other-project/secret.env ❌实际影响:
- Claude 不能偷看你的 SSH 密钥、系统配置、其他项目的源代码
- 如果你的项目中有子模块或符号链接指向项目外路径,可能被限制访问
- 如果你需要 Claude 操作项目外文件(如全局配置文件),需要显式授权
注意:这个限制主要作用于工具调用。如果你是 VSCode 用户,VSCode 本身打开的文件不受此限制——Claude 可以通过对话上下文"看到"你当前打开的任意文件。这是你需要留意的一个边界情况。
网络请求:必须通过审计工具
Claude Code 本身不直接发起网络请求。所有网络访问必须通过两个可审计的工具:
| 工具 | 用途 | 审计方式 |
|---|---|---|
| WebFetch | 抓取指定 URL 的内容 | 请求 URL 和返回内容完全可见 |
| WebSearch | 搜索网络 | 搜索关键词和执行结果可见 |
Bash(curl:*) 和 Bash(wget:*) 是 Shell 命令,受权限规则控制。如果你在 deny 中禁止了它们(强烈建议),Claude 就无法通过 Shell 进行网络访问。
这意味着:Claude 的所有网络活动都是可追溯的。你知道它访问了哪个 URL、搜索了什么关键词、拿到了什么结果。不存在隐形的网络调用。
Shell 命令:子进程,不影响主 Shell
Claude Code 执行的每一条 Shell 命令都在独立的子进程中运行:
- 不会修改你的 Shell 环境变量(
export、set对主 Shell 无效) - 不会改变你的工作目录(
cd只在子进程内生效) - 不会污染你的 Shell 历史(子进程退出即消失,不在
.bash_history中) - 不会修改你的 Shell 配置(
.bashrc、.zshrc不受影响)
这意味着即使 Claude 执行了 export DATABASE_URL=wrong-value 或 cd /tmp,你的终端环境完全不受影响。每次 Bash 调用是一个干净的子进程。
环境变量:不自动读取敏感文件
Claude Code 不会自动读取 .env 文件或其他环境变量配置文件。
.env文件的内容不会被自动注入到 Claude 的上下文中- 你需要在
settings.json的env字段中显式声明 Claude 可以使用的环境变量 - 敏感数据(如
DATABASE_URL、API_SECRET)放在settings.local.json中,不提交到 Git
// .claude/settings.local.json(不提交 Git)
{
"env": {
"DATABASE_URL": "postgresql://localhost:5432/dev",
"API_SECRET": "sk-dev-xxxx"
}
}⚠️ 即使配置在 settings.local.json 中,Claude Code 也不会主动把这些值发送到外部。 但 Claude 可以通过 Bash 命令访问这些环境变量。确保你的 deny 规则阻止了网络外联(curl / wget),以防止任何可能的泄露路径。
14.6 安全最佳实践
以下十条实践来自社区经验和实际踩坑总结,按重要性排列。
1. 最小权限原则
先想清楚 Claude 最少需要什么权限才能完成工作,只开放那些。
不要一上来就复制效率优先配置中的 Bash(git:*)。问自己:Claude 真的需要 git push 吗?真的需要 npm install 吗?从最小的 allow 列表开始,遇到确认弹窗太频繁时再逐步添加。
2. deny 优先
deny 规则是你安全策略的基石。即使 allow 列表写得很宽松,只要 deny 覆盖了真正的危险操作,系统就是安全的。
deny 列表至少应该包含:
Bash(rm:-rf:*)— 递归强制删除Bash(sudo:*)— 提权操作Bash(curl:*:* |*:bash)— 从远程下载并执行代码
3. 项目级配置共享给团队
安全规则放在 .claude/settings.json(项目配置)中,并提交到 Git。这样:
- 新成员加入项目时,自动获得安全配置
- 安全规则可以被 Code Review
- 配置变更可追溯(谁在什么时候改了什么)
.claude/
settings.json ← 提交:团队共享的安全规则
settings.local.json ← 不提交:个人凭据和本地覆盖4. 敏感信息保护
API 密钥、数据库连接字符串、私有令牌等敏感信息,永远不要出现在以下位置:
- ❌ 项目
.claude/settings.json(会提交到 Git) - ❌ CLI 命令中(会出现在对话历史里)
- ❌ CLAUDE.md(会提交到 Git 并被模型读取)
- ✅
.claude/settings.local.json的env字段 - ✅ 全局
~/.claude/settings.json的env字段(不上传) - ✅ 操作系统的环境变量
5. 定期审查规则
权限规则不是"设完就忘"的东西。建议每 2-4 周检查一次:
- allow 列表中是否有不再需要的权限?(如项目早期为了调试加了
Bash(curl:*),后来忘了移除) - deny 列表中是否有新出现的危险模式需要加入?(如项目引入了 Docker,需要加
Bash(docker:rm:*)) - 是否有操作频繁弹出确认但其实很安全?考虑加入 allow
6. deny 在任何模式下都生效
重申一次,因为这太重要了:Bypass 模式不会绕过 deny 规则。
很多用户误以为:"我开了 Bypass,所以安全全靠我自己盯着。"这是危险的误解。deny 规则是 Claude Code 的硬限制——即使 Bypass 模式下,rm -rf / 也会被拒绝。
这也是为什么我们反复强调精心设计 deny 列表而不是依赖模式选择来保证安全。
7. 环境隔离
为不同环境使用不同的配置策略:
开发环境 (.claude/settings.json 项目配置):
allow: 宽松 — 包管理、Git、文件操作
deny: 核心 — rm -rf、sudo、curl | bash
预发布/staging:
allow: 中等 — 只运行已有脚本,不修改依赖
deny: 严格 — rm *、push *、commit *
生产环境:
allow: 极窄 — 只读操作
deny: 全面 — 所有写入和网络8. 审计日志
Claude Code 的所有操作都有记录。定期检查:
- Git log:Claude 的每次提交都有迹可循
- 对话历史:VSCode 扩展中的历史会话(时钟图标)
- Shell 历史:虽然子进程不影响主 Shell,但命令执行记录在对话面板中可展开查看
养成在重要操作后扫一眼 Git diff 的习惯——这比任何配置都更能保护你的代码。
9. 网络限制
除非你明确需要 Claude 从外部获取信息(如查阅最新文档、搜索解决方案),否则禁止所有网络工具:
{
"deny": [
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(nc:*)",
"Bash(ssh:*)",
"Bash(telnet:*)",
"Bash(scp:*)",
"Bash(sftp:*)",
"Bash(rsync:*:*://*)"
]
}如果允许 WebFetch 和 WebSearch(这是合理的需求),确保在 deny 中阻止了 Shell 级别的网络访问——这两个不是一个通道。
10. Git 保护
Git 是 Claude Code 操作的主要战场之一,也是需要精细保护的领域:
{
"deny": [
"Bash(git:push:--force:*)",
"Bash(git:push:-f:*)",
"Bash(git:reset:--hard:*)",
"Bash(git:clean:-fd:*)",
"Bash(git:branch:-D:*)"
]
}被保护的这些操作各有原因:
push --force:覆盖远程历史,团队其他人的工作可能丢失reset --hard:丢弃本地未提交的工作clean -fd:删除未跟踪的文件和目录branch -D:强制删除分支(即使未合并)
14.7 常见安全场景
以下五个场景来自实际使用中的典型安全需求,每个都附带了推荐的解决方案。
场景 1:阻止意外删除
问题:Claude 在处理"清理项目中的临时文件"这类任务时,可能生成 rm -rf 命令。如果路径计算错误或上下文理解偏差,可能删除不该删的文件。
解决方案:
{
"deny": [
"Bash(rm:-rf:*)",
"Bash(rm:-r:*)",
"Bash(rmdir:*)",
"Bash(find:*:-delete)",
"Bash(find:*:-exec:rm:*)"
]
}最后一行的 find ... -exec rm 是容易被忽视的删除路径——很多用户只 deny 了 rm,但忘了 find 也能删除文件。find ... -delete 同理。
更好的做法:当你需要 Claude 清理文件时,让它列出要删除的文件清单,你手动检查后再让它执行。这就是 Plan mode 的典型使用场景(见第 9 章)。
场景 2:防止代码泄露
问题:Claude 在处理"帮我查一下这个 API 的用法"时,可能执行 curl 请求向外部服务发送你的代码片段或数据。
解决方案:
{
"deny": [
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(nc:*)",
"Bash(http:*)",
"Bash(httpx:*)",
"Bash(python:*:requests*)",
"Bash(node:*:fetch*)",
"Bash(node:*:axios*)"
]
}同时也拒绝通过编程语言运行时发送网络请求(如 python -c "import requests; ...")。不过这类规则较难覆盖全面——脚本中的网络调用路径太多了。最可靠的防线还是禁止所有网络相关的 Shell 命令,只允许通过 WebFetch / WebSearch 这两个可审计的工具访问网络。
场景 3:保护生产环境
问题:开发时使用的 Claude Code 配置如果在包含生产环境凭据的项目中执行,可能触及生产数据库或服务器。
解决方案:为生产相关项目创建独立的严格配置。
// production-project/.claude/settings.json
{
"permissions": {
"allow": [
"Bash(git:status)",
"Bash(git:diff)",
"Bash(git:log)",
"Bash(ls:*)",
"Bash(cat:*)",
"Bash(head:*)",
"Bash(tail:*)"
],
"deny": [
"Bash(rm:*)",
"Bash(sudo:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(git:push*)",
"Bash(git:commit*)",
"Bash(kubectl:*)",
"Bash(docker:*)",
"Bash(ssh:*)",
"Bash(scp:*)",
"Bash(terraform:*)",
"Bash(ansible:*)",
"Bash(aws:*)",
"Bash(gcloud:*)"
]
}
}关键思路:生产项目配置中,Claude 被限制为纯分析角色——可以读代码、看 git 状态,但任何对基础设施的操作(kubectl、docker、terraform、aws)都在 deny 列表中。需要执行这些操作时,你自己来。
场景 4:新人安全
问题:团队新成员刚接触 Claude Code,还不了解它的行为边界。过于宽松的权限可能导致他们意外接受了 Claude 的不当操作。
解决方案:新成员的初始配置应该保守,随着熟悉度提升逐步放宽。
第一周:
- 权限模式:Ask(每步确认)
- allow:只读操作(ls、cat、git status/diff/log)
- deny:全部危险操作
第二至四周:
- 权限模式:Auto
- allow:加入包管理脚本运行、git add/commit
- deny:保持不变
一个月以上:
- 权限模式:Auto / Bypass
- allow:根据实际需要逐步添加
- deny:根据项目风险调整这个渐进策略不是不信任新人,而是让他们通过观察 Claude 的行为来建立判断力。直接给新人 Bypass 模式就像让第一天上班的同事直接操作生产数据库——不是能力问题,而是对系统的了解还没有建立。
场景 5:开源项目安全
问题:公开仓库中的 .claude/settings.json 会被所有人看到。如果配置中包含特定路径或内部工具名称,可能泄露项目内部信息。
解决方案:
// .claude/settings.json(提交到公开仓库)
{
"permissions": {
"allow": [
"Bash(git:status)",
"Bash(git:diff)",
"Bash(git:log)",
"Bash(pnpm:run:*)",
"Bash(npm:run:*)",
"Bash(ls:*)",
"Bash(cat:*)"
],
"deny": [
"Bash(rm:-rf:*)",
"Bash(sudo:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(git:push:--force:*)"
]
}
}注意事项:
- 不要在任何提交到公开仓库的文件中硬编码路径、服务器地址、内部工具名称
- 敏感的环境变量放在
settings.local.json(已在.gitignore中,不提交) - 项目特定的安全约束(如禁止访问某个内部 API)放在
settings.local.json中,而非settings.json - CLAUDE.md 中不要写任何凭据、密钥、或内部服务的访问信息
14.8 本章小结
本章是进阶篇的最后一章,也是从"会用 Claude Code"到"安全地用 Claude Code"的关键过渡。
核心知识回顾
- 权限系统是三层架构:allow / deny 规则 → 权限模式(Ask/Edit/Auto/Plan/Bypass)→ 安全沙箱。三层叠加,缺一不可。
- deny 永远优先:与书写顺序无关、与权限模式无关。精心设计 deny 列表是安全的第一要务。
- 规则语法灵活且精确:从
Bash(git:status)的精确匹配到Bash(git:*)的通配符,你可以实现任意粒度的控制。 - 不同环境不同策略:个人开发、团队协作、CI/CD 需要完全不同的权限模板。没有"一套配置走天下"。
- 安全沙箱是硬性底线:文件访问限制、网络审计、子进程隔离、环境变量保护——这些不需要你配置,默认生效。
- 十条最佳实践是行动的指南:从最小权限原则到 Git 保护,每一条都为防止一个具体的风险。
从进阶篇到生态篇
理解了权限体系,你可能会想:"如果要给 Claude Code 添加新的能力——比如连接数据库、调用第三方 API、自定义自动化流程——如何安全地做到?"这就是下一篇要回答的问题。
在第四篇:生态篇中,我们将探索如何通过以下方式安全地扩展 Claude Code 的能力:
- 第 15 章:MCP 协议详解 — 通过标准化的协议接入外部工具和数据源,同时保持沙箱安全
- 第 16 章:插件系统 — 安装和管理社区插件,理解插件的权限模型
- 第 17 章:Skills 体系 — 自定义可复用的能力,Skills 的权限边界
- 第 18 章:Hooks 机制 — 在工具调用前后注入自定义逻辑,安全审计和流程控制
权限体系是生态扩展的安全前提。理解了 allow / deny / sandbox 三层防护,你才能判断:一个 MCP 服务器应该接入哪些数据库?一个 Plugin 应该被授予什么权限?一个 Skill 的执行边界在哪里?
章节小结:本章覆盖了 Claude Code 权限系统的完整知识——从架构原理到规则语法,从配置模板到最佳实践,从安全场景到扩展路径。权限配置不是一次性的设置,而是一个随项目演进而持续调整的过程。从小权限开始,逐步添加信任,永远保留 deny 作为安全底线——这是安全使用 Claude Code 的核心方法论。
下一章,我们将迈入生态篇,从 MCP 协议开始,探索如何安全地让 Claude Code 连接更广阔的世界。