Skip to content
Published at:

第 14 章:权限与安全

在第 9 章中,我们学习了五种权限模式(Ask / Edit / Plan / Auto / Bypass)——它们控制的是 Claude Code 是否向你确认。但权限模式只是安全体系的第一层。当你把规则从"每步都问"升级到"自动执行"时,真正保护你代码安全的是背后的 allow / deny 规则系统

本章深入 Claude Code 的权限架构:规则如何匹配、deny 为什么永远优先、如何为不同环境设计合适的权限策略。这是进阶篇的最后一章,也是从"会用 Claude Code"通向"安全地用 Claude Code"的关键桥梁。

本章目标:理解权限系统的完整架构,掌握 allow / deny 规则的语法和优先级,能根据项目类型和环境设计安全的权限配置。

14.1 权限系统架构

Claude Code 的权限系统是一个多层过滤架构。每次工具调用都要经过层层检查,最终产生三种结果之一。

权限检查流程

flowchart TB A["Claude 发起工具调用"] --> B{"Bypass 模式?"} B -->|"是"| C{"deny 规则匹配?"} B -->|"否"| D{"allow 规则匹配?"} C -->|"是"| DENY["🔴 Auto-deny<br>(deny 规则永远生效)"] C -->|"否"| ALLOW["🟢 Auto-allow<br>(Bypass 下直接放行)"] D -->|"是"| ALLOW2["🟢 Auto-allow"] D -->|"否"| E{"deny 规则匹配?"} E -->|"是"| DENY2["🔴 Auto-deny"] E -->|"否"| F{"风险等级"} F -->|"低风险"| ALLOW3["🟢 Auto-allow<br>(如 Read、ls)"] F -->|"中风险"| ASK["🟡 Ask user<br>(如 Write、git commit)"] F -->|"高风险"| ASK2["🔶 始终确认<br>(如 rm、sudo)"] style DENY fill:#ffcdd2 style DENY2 fill:#ffcdd2 style ALLOW fill:#c8e6c9 style ALLOW2 fill:#c8e6c9 style ALLOW3 fill:#c8e6c9 style ASK fill:#fff9c4 style ASK2 fill:#ffcc80

这个流程有几个关键点值得注意:

  1. deny 是绝对优先的:即使 Bypass 模式下,deny 规则仍然生效。你不可能通过切换模式来绕过 deny 规则。这是一个刻意的安全设计。
  2. allow 规则让你跳过确认:在没有 Bypass 的情况下,allow 规则作用的对象不再弹出确认窗口,直接执行。这是"效率优先"的实现方式。
  3. 没有规则匹配时,走默认风险评估: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.jsonpermissions.allowpermissions.deny 数组中。每一条规则是一个字符串,描述了匹配哪些工具调用。

规则格式

规则的基本格式为 工具名称(参数模式)

工具名称(参数1:参数2:...)

工具名称支持 Claude Code 的所有核心工具:ReadWriteEditBashWebSearchWebFetchTodoWriteTaskOutput 等。其中 Bash 是最常用也最需要精细控制的工具——因为它能执行任意 Shell 命令。

匹配模式详解

精确匹配

匹配一个完全确定的命令,不包含任何通配符:

json
{
  "allow": [
    "Bash(git:status)",
    "Bash(git:diff)",
    "Bash(git:log)",
    "Bash(pnpm:install)",
    "Bash(node:--version)"
  ]
}

Bash(git:status) 只匹配 git status,不匹配 git status --shortgit stash。精确匹配适合你完全信任且频繁使用的特定命令。

通配符匹配

* 匹配任意参数:

json
{
  "allow": [
    "Bash(git:*)",       // 匹配所有 git 命令
    "Bash(pnpm:*)",      // 匹配所有 pnpm 命令
    "Bash(npm:*)",       // 匹配所有 npm 命令
    "Bash(ls:*)",        // 匹配 ls 的所有变体
    "Bash(cat:*)"        // 匹配 cat 的所有调用
  ]
}

Bash(git:*) 匹配 git statusgit diffgit commitgit push 等一切以 git 开头的命令。这是最常用的匹配模式——你信任某个工具链(如 gitpnpm),但不限制具体子命令。

深层参数匹配

* 可以出现在命令的任意位置,匹配一部分参数:

json
{
  "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 操作
  ]
}

危险模式匹配

用精确的深层匹配来拦截特定危险模式:

json
{
  "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,冒号对应空格。如果命令中有管道或重定向符号(|>>>),这些字符在规则中也按字面匹配。

无参数工具规则

对于不需要参数的工具(如 WebSearchWebFetch),规则只写工具名称:

json
{
  "allow": [
    "WebSearch",    // 允许所有 Web 搜索
    "WebFetch"      // 允许所有 Web 抓取
  ],
  "deny": []
}

对于 ReadWriteEdit,规则中可以包含文件路径模式:

json
{
  "allow": [
    "Read(*)",       // 允许读取任何文件
    "Write(src/**)", // 允许写入 src/ 下的任何文件
    "Edit(src/**)"   // 允许编辑 src/ 下的任何文件
  ],
  "deny": [
    "Write(.env)",           // 禁止写入 .env 文件
    "Write(**/*.secret.*)",  // 禁止写入任何 .secret.* 文件
    "Read(**/*.pem)"         // 禁止读取私钥文件
  ]
}

规则优先级:deny 永远胜出

权限系统的核心原则只有一条:

deny 永远优先于 allow。与规则的书写顺序无关。

json
{
  "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 精确地"挖掉"你不想要的子集。这是一种安全且高效的做法——先开门,再锁上不该开的窗户。

规则评估逻辑(伪代码)

python
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 做只读操作,一切有副作用的操作都需要确认:

json
{
  "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 的行为建立了信任,可以扩大到允许日常开发工具链的自动执行:

json
{
  "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 的判断,通配符覆盖更广。

高级配置:精细控制每一个工具链

当项目有明确的安全边界时,你可以对每个工具链进行精细的拆解:

json
{
  "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 风格优点缺点适用
宽松 allowBash(git:*) 一把梭配置简洁,少写规则deny 必须精确,遗漏风险信任度高的小项目
精细 allow逐子命令列出安全边界清晰,意外行为也会被捕获配置长,维护成本高多人协作、敏感项目
混合策略信任的用通配符,存疑的用精确匹配平衡效率和安全性需要判断哪些该宽松推荐:大多数项目

14.4 常见权限配置模板

根据环境的不同,权限配置的策略应该有所区别。以下是三种典型场景的配置模板。

个人开发环境

这是最宽松的配置,适合个人项目、本地实验、学习练习。核心原则:信任工具链,只拦截真正的破坏性操作

json
{
  "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 的破坏性操作

json
{
  "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 通常以非交互模式运行。权限配置的目标不是减少确认弹窗,而是精确控制它能做什么、不能做什么

json
{
  "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 环境变量(exportset 对主 Shell 无效)
  • 不会改变你的工作目录(cd 只在子进程内生效)
  • 不会污染你的 Shell 历史(子进程退出即消失,不在 .bash_history 中)
  • 不会修改你的 Shell 配置(.bashrc.zshrc 不受影响)

这意味着即使 Claude 执行了 export DATABASE_URL=wrong-valuecd /tmp,你的终端环境完全不受影响。每次 Bash 调用是一个干净的子进程。

环境变量:不自动读取敏感文件

Claude Code 不会自动读取 .env 文件或其他环境变量配置文件。

  • .env 文件的内容不会被自动注入到 Claude 的上下文中
  • 你需要在 settings.jsonenv 字段中显式声明 Claude 可以使用的环境变量
  • 敏感数据(如 DATABASE_URLAPI_SECRET)放在 settings.local.json 中,不提交到 Git
json
// .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.jsonenv 字段
  • ✅ 全局 ~/.claude/settings.jsonenv 字段(不上传)
  • ✅ 操作系统的环境变量

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 从外部获取信息(如查阅最新文档、搜索解决方案),否则禁止所有网络工具:

json
{
  "deny": [
    "Bash(curl:*)",
    "Bash(wget:*)",
    "Bash(nc:*)",
    "Bash(ssh:*)",
    "Bash(telnet:*)",
    "Bash(scp:*)",
    "Bash(sftp:*)",
    "Bash(rsync:*:*://*)"
  ]
}

如果允许 WebFetchWebSearch(这是合理的需求),确保在 deny 中阻止了 Shell 级别的网络访问——这两个不是一个通道。

10. Git 保护

Git 是 Claude Code 操作的主要战场之一,也是需要精细保护的领域:

json
{
  "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 命令。如果路径计算错误或上下文理解偏差,可能删除不该删的文件。

解决方案

json
{
  "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 请求向外部服务发送你的代码片段或数据。

解决方案

json
{
  "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 配置如果在包含生产环境凭据的项目中执行,可能触及生产数据库或服务器。

解决方案:为生产相关项目创建独立的严格配置。

json
// 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 会被所有人看到。如果配置中包含特定路径或内部工具名称,可能泄露项目内部信息。

解决方案

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"的关键过渡。

核心知识回顾

  1. 权限系统是三层架构:allow / deny 规则 → 权限模式(Ask/Edit/Auto/Plan/Bypass)→ 安全沙箱。三层叠加,缺一不可。
  2. deny 永远优先:与书写顺序无关、与权限模式无关。精心设计 deny 列表是安全的第一要务。
  3. 规则语法灵活且精确:从 Bash(git:status) 的精确匹配到 Bash(git:*) 的通配符,你可以实现任意粒度的控制。
  4. 不同环境不同策略:个人开发、团队协作、CI/CD 需要完全不同的权限模板。没有"一套配置走天下"。
  5. 安全沙箱是硬性底线:文件访问限制、网络审计、子进程隔离、环境变量保护——这些不需要你配置,默认生效。
  6. 十条最佳实践是行动的指南:从最小权限原则到 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 连接更广阔的世界。