安全与权限控制
7.2 节解决的是"AI 看到了什么",本节解决的是"AI 能做什么"。再清晰的上下文,如果配上"无差别执行权限",依然会带来灾难——一次未受控的 rm -rf、一次错误的生产数据库迁移、一次把 API Key 推到公开仓库——这些事故的根源不是 AI 不够聪明,而是人类没有把权限边界设计清楚。
本节的核心论点是:Claude Code 不是"自动驾驶",而是"高级巡航辅助"——它能在大部分场景下减轻工程师的负担,但任何一次"接管方向盘"的动作都必须由人类拍板。这条原则不依赖 AI 能力的高低——哪怕未来 LLM 变得几乎无错,"人类对关键决策保留最终责任"依然是工程伦理与法律责任的底线。本节会把这条原则拆成"权限三层模型 → Claude Code 机制 → 高风险动作 → 信任分级 → 反模式 → 团队共识"六部分,给出一份可以立即套用的配置模板与对话脚本。
需要先澄清一个常见误解:安全设计不是"技术问题",更不是"偏执问题",而是"组织问题"。一个团队的安全水平由该团队"最薄弱的那个工程师在最累的那一晚做的决定"决定——不是由最严格的 settings.json 决定。本节给出的所有工具与流程,都应当配套相应的团队文化才能真正发挥作用:
- 工具阻断(settings.json deny)告诉团队"这件事禁止做"。
- 流程检查(Hooks、Plan)告诉团队"做这件事前请三思"。
- 审计日志(incidents.md)告诉团队"我们曾经犯过哪些错"。
- 文化共识(安全公约)告诉团队"我们想成为什么样的工程组织"。
四者缺一不可。光靠工具阻断会让团队感觉"被工具束缚",进而想方设法绕过;光靠文化共识没有工具兜底,会在压力情境下崩溃。只有四者协同,AI 协作时代的安全边界才能既高效又坚固。读者在阅读后续章节时,应当持续问自己——"这条建议在我团队是有工具支持还是仅靠自觉?"——这个问题决定了建议的实际有效性。
一、AI 协作时代的"权限三层模型"
1.1 执行层(Execution):AI 可以代为完成的动作
执行层指那些可逆、低影响半径、错了能轻松回滚的动作。这一层应当尽可能授权给 AI,让工程师从机械劳动中解放出来:
- 修改源代码(在 git 工作区、未提交时)
- 创建/删除测试文件
- 跑单元测试、跑 lint、跑 typecheck
- 生成文档草稿
- 重命名变量、重构函数签名
- 安装开发依赖(dev dependencies)
判断"是否属于执行层"的简易标准——如果出错,单条 git checkout 或 git reset 就能恢复,那就属于执行层。
1.2 审查层(Review):AI 提议、人类把关的动作
审查层指那些有一定影响半径、错了挽回有成本、但通过 review 可以发现问题的动作。这一层 AI 可以"提议",但执行权握在人类手里:
- git commit / git merge
- 修改 CI/CD 配置
- 升级生产依赖(production dependencies)
- 修改数据模型 schema
- 修改 API 契约
- 修改 CLAUDE.md / Skills(影响后续 AI 行为)
这一层最适合 Plan 模式——AI 输出完整 plan,人类审批后再执行。
1.3 决策层(Decision):必须由人类原创的判断
决策层指那些不可逆、高影响半径、错了会带来商业/法律/伦理后果的动作。这一层 AI 永远不能代为决策:
- 部署到生产环境
- 执行数据库 schema 迁移(含数据迁移)
- 操作密钥、Token、生产配置
- 删除 git 分支、强制推送(force push)
- 处理用户隐私数据
- 选择架构方向、技术栈、商业模型
- 法律合规相关的代码(数据合规、用户协议)
决策层的边界不应该写死在某个工具里,而应该作为团队共识贴在团队墙上、写进 CLAUDE.md、写进 onboarding 文档。
1.4 三层模型如何映射到具体场景
不同阶段的工作流对应不同的层级分布:
| 阶段 | 执行层 | 审查层 | 决策层 |
|---|---|---|---|
| 开发 | 写代码、写测试、跑测试 | git commit、PR 描述、依赖升级 | 架构决策、技术选型 |
| 代码审查 | 自动 lint、风格检查 | AI 一次审 + 人审 | merge 决策、回归批准 |
| 部署 | 构建、跑 CI、生成 changelog | 灰度策略、回滚 plan | 推全量、紧急回滚 |
| 运维 | 日志解析、根因假设 | 故障复盘起草 | 事故级别判定、对外沟通 |
| 数据 | 查询、聚合、报表 | 修改 ETL 任务 | schema 迁移、数据删除 |
这张表不是死规定,而是起点。每个团队应该基于自己的业务风险特征,把表格中的条目重新分配。例如金融业务可能把"修改 API 契约"也提到决策层;个人项目可能把"灰度策略"下放到执行层。
层级判定的边界场景:现实中很多动作处于三层之间的灰色地带,例如——
- "改 README 里的安装命令":看似执行层(文档变更可逆),但如果命令带有
npm install -g这类全局副作用,错的命令复制粘贴执行可能伤害用户机器,应当升级到审查层。 - "回复用户工单":看似执行层(文字内容可改),但回复一旦发出,用户的预期已经形成、品牌印象已经留下,应当属于审查层。
- "调整一个营销 A/B 实验比例":看似审查层(流量切换可回滚),但如果实验涉及付费用户的功能差异,可能涉及合同义务,应当升级到决策层。
判断灰色地带的简易标准——问"如果错了,谁会受伤"。只伤工程师本人 → 执行层;伤队友/项目 → 审查层;伤用户/公司/法律责任 → 决策层。这条标准比"动作可不可逆"更直接,因为它聚焦在伤害的承担者而非动作本身。
二、Claude Code 的权限机制
2.1 Permission Mode
Claude Code 支持四种权限模式:
| 模式 | 行为 | 适用场景 |
|---|---|---|
default | 工具调用前弹出确认提示 | 日常开发、新接入项目 |
acceptEdits | 编辑类工具自动通过、其他类型仍需确认 | 代码迭代密集期 |
bypassPermissions | 跳过所有确认(危险) | 仅限可一键销毁的沙盒环境 |
plan | 任何写动作前先输出 Plan 等审批 | 高风险变更、首次接触陌生代码 |
启动时通过 --permission-mode 指定:
# 普通开发
claude
# 高频迭代期
claude --permission-mode acceptEdits
# 高风险变更
claude --permission-mode plan
# 沙盒/演示(绝不在生产相关项目使用)
claude --permission-mode bypassPermissions
会话中也可以临时切换:在对话框输入 /plan 进入 Plan 模式、/acceptEdits 切回快速模式。
铁律:生产相关项目永远不开 bypassPermissions。哪怕只是"快速跑一下",下次有人接手这台机器时可能会吃大亏。
2.2 .claude/settings.json 的 allow / deny 列表
settings.json 提供了细粒度的工具白名单与黑名单。一份典型的"安全 baseline"配置:
{
"permissions": {
"allow": [
"Bash(pnpm test:*)",
"Bash(pnpm lint:*)",
"Bash(pnpm typecheck)",
"Bash(pnpm build)",
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Edit(src/**)",
"Write(src/**)",
"Read(**)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force*)",
"Bash(git reset --hard*)",
"Bash(npm publish:*)",
"Bash(pnpm publish:*)",
"Bash(docker push:*)",
"Bash(kubectl:*)",
"Bash(terraform apply:*)",
"Read(.env)",
"Read(.env.*)",
"Read(**/.env)",
"Read(**/secrets/**)",
"Edit(.env*)",
"Edit(**/.env*)",
"Edit(.github/workflows/*-deploy.yml)"
]
}
}
allow 是"无需确认即可执行"的白名单,deny 是"无论如何都禁止执行"的黑名单。deny 优先级高于 allow——任何写在 deny 中的动作都会被硬阻断。
2.3 Hooks 作为执行前/后的"主动守卫"
Hooks 提供了比 allow/deny 更灵活的自定义守卫。一份用于"防止意外提交大文件"的 hook:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$TOOL_INPUT\" | grep -qE 'git (add|commit)' && find . -type f -size +5M -not -path './node_modules/*' -not -path './.git/*' | head -1 | grep -q .; then echo 'BLOCKED: 仓库中存在 > 5MB 的文件,请确认是否应该忽略' >&2; exit 1; fi"
}
]
}
]
}
}
Hook 退出码非 0 会阻断该次工具调用,并把 stderr 内容回送给 Claude——Claude 会自然地进入"修复或绕开"的对话模式。
更复杂的场景可以接入外部脚本:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/check-secret-leak.js \"$TOOL_INPUT\""
}
]
}
]
}
}
.claude/hooks/check-secret-leak.js 可以是一段自定义脚本——例如检查目标文件是否含 .env/secrets/token 等敏感字段。
2.4 Plan 模式:把"自动执行"降级为"人工审批"
Plan 模式是高风险变更场景的"刹车系统"。在该模式下,Claude 不能直接调用 Edit/Write/Bash 等"会改变状态"的工具,必须先输出一份完整的 Plan,等用户点击"批准"后才能执行。
最适合 Plan 模式的场景:
- 首次接入一个陌生代码库
- 涉及多文件、多依赖的大型重构
- 涉及生产环境配置的修改
- 涉及 git 历史改写的操作(rebase / cherry-pick)
- 任何团队 review 前的"试运行"
启用方式:在会话中输入 /plan,或启动时加 --permission-mode plan。
2.5 工具粒度的权限——Bash 全开 vs 限定命令
最危险的默认配置是 "Bash(*)"。它意味着 Claude 可以执行任意 shell 命令——包括 rm -rf、curl <恶意 URL> | sh、npm install <typo-squatting-package>。永远不要给 Bash 全开权限。
正确的做法是按命令前缀分组:
{
"permissions": {
"allow": [
"Bash(pnpm test*)",
"Bash(pnpm lint*)",
"Bash(pnpm format*)",
"Bash(pnpm typecheck)",
"Bash(pnpm build)",
"Bash(node --version)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git branch)",
"Bash(ls *)",
"Bash(cat README.md)",
"Bash(rg *)",
"Bash(fd *)"
]
}
}
这种"白名单具体命令"的方式让 Claude 在常规开发任务中无障碍工作,但任何一条不在白名单上的命令都会触发确认。信任建立在"我清楚 AI 能做什么"的基础上。
白名单维护的反模式与对策:实际项目中,白名单会随着团队工作流变化逐渐膨胀,最终走向两个极端——
- 极端 A:白名单过短:每天数十次"please confirm"打断工程师,最终团队选择关掉确认(即变相走向
bypassPermissions),所有的安全设计前功尽弃。 - 极端 B:白名单过长:白名单逐渐添加到几十上百条,包含了实际并不该自动放行的命令(例如
git rebase、pnpm publish:test),团队也不再 review,安全形同虚设。
对策:
- 每月做一次白名单 review:打开 settings.json,逐条确认"这条规则是否还在使用?是否仍然安全?"。把不再使用的删除、把过宽的收紧。
- 建立"命令使用频率统计":通过 Hooks 在每次工具调用时记录命令到日志,月底做一份"高频命令排行",把高频但目前每次都需确认的命令评估是否纳入白名单。
- 白名单分组:按风险等级把白名单拆成
"safe-readonly"、"safe-build"、"safe-dev-deps"等分组,让维护者一眼看出哪些是低风险、哪些需要谨慎。
三、五类典型高风险动作的边界
3.1 写入生产数据库 / 执行 schema 迁移
数据库迁移是软件工程史上"最容易导致大事故"的环节之一。一次错误的 ALTER TABLE 可能导致 schema 不一致、数据丢失、长时间锁表。
铁律:
- 生产数据库的连接字符串永远不出现在 prompt 中。
- Claude 只生成 migration 脚本,不直接执行。
- 所有 migration 必须在 staging 环境跑过、被 review、再 merge。
- 生产 migration 由人类工程师手动触发——
pnpm migrate:prod这样的命令永远不应被加入 allow 列表。
让 Claude 协助起草 migration:
请基于 src/user/types.ts 中的 User 接口变更,生成对应的 SQL migration:
- 工具:drizzle-kit generate
- 文件:drizzle/migrations/0042_add_phone_number.sql
- 必须包含 up + down 两个方向
不要执行 drizzle-kit migrate,仅生成脚本。我审阅后由 DBA 在生产手动执行。
生产数据库变更的"四关审批流":成熟团队通常会把生产 migration 拆成四道关,避免单点错误:
- 第一关:开发者本地——Claude 生成 migration,开发者审阅 SQL 是否正确、是否有破坏性。
- 第二关:Code Review——队友审阅 migration 的 up/down 双向是否对称、索引是否合理、锁表风险是否可控。
- 第三关:Staging 全量演练——在 staging 环境对生产快照执行一遍 migration,验证耗时、空间、回滚是否正常。
- 第四关:生产维护窗口手动执行——DBA 或值班 SRE 在公司维护窗口期手动执行,全程录屏、监控、保留回滚开关。
四关之间不能跳过。任何一关跳过都意味着把"防御纵深"变成了"单点防御"——很多大事故的复盘都能追溯到"为了赶进度跳过了某一关"。Claude 在这条流水线里只参与第一关,其余三关都需要人类完整介入。
3.2 推送到远端 / 操作生产环境
git push、docker push、kubectl apply 这类"把本地状态推向远端"的命令,应当全部加入 deny 列表,并由人类工程师手动确认后执行。
{
"permissions": {
"deny": [
"Bash(git push:*)",
"Bash(docker push:*)",
"Bash(kubectl apply:*)",
"Bash(kubectl delete:*)",
"Bash(helm upgrade:*)",
"Bash(terraform apply:*)",
"Bash(aws s3 cp:*)",
"Bash(gcloud deploy:*)"
]
}
}
如果 Claude 提议执行这些命令,工程师可以选择"批准一次",但永远不要把它们加入 allow 列表——单次批准的成本是 5 秒钟,全局放权的成本可能是整个生产环境。
3.3 安装/升级依赖(供应链攻击防御)
供应链攻击(Supply Chain Attack)是近年来最常见的安全威胁之一。攻击者通过发布"包名错字"型恶意包(如 react-dom-2、lodaash)或污染合法包(如 ua-parser-js 事件),让开发者在不知情的情况下引入恶意代码。
让 Claude 自动 pnpm add 或 pnpm update 是高风险的——它可能基于过期的训练数据推荐已被废弃或被攻击的包。正确做法是 Claude 提议,人类核对:
请推荐一个 TypeScript 写的 CSV 解析库,用于服务端处理大文件。
要求:
1. 列出 3 个候选,按 GitHub stars 与 npm 周下载排序
2. 标注每个包的最近一次 release 日期与维护活跃度
3. 不要直接执行 pnpm add,等我确认后我手动执行
工程师收到推荐后,应当逐个核对:
- 包名是否拼写正确(防错字攻击)
- 维护者是否可信(GitHub 历史、社区评价)
- 最近一次 release 时间(避免引入"被弃坑"的包)
- 是否有已知 CVE 漏洞
3.4 操作密钥、Token、生产环境配置
密钥管理的"三铁律":
- 永远不在 prompt 中粘贴真实密钥——用
<API_KEY>占位符。 - 永远不让 Claude 读
.env/.env.local/secrets/*——通过 deny 规则硬阻断。 - 永远不让 Claude 修改
.env——同上。
配置示例:
{
"permissions": {
"deny": [
"Read(.env)",
"Read(.env.*)",
"Read(**/.env)",
"Read(**/.env.*)",
"Read(**/secrets/**)",
"Read(**/credentials/**)",
"Edit(.env)",
"Edit(.env.*)",
"Edit(**/.env)",
"Edit(**/.env.*)",
"Write(.env)",
"Write(.env.*)"
]
}
}
并把这条规则写进 CLAUDE.md:
## 安全铁律
- 任何 .env / secrets / credentials 文件,Claude 不读、不写、不引用
- prompt 中遇到密钥,一律用 <API_KEY> / <TOKEN> 占位
- 调试需要真实值时,工程师本地手动操作,不引入 Claude
3.5 跨仓库/跨项目的"全局影响"动作
某些动作虽然技术上无害,但会跨越项目边界产生连锁影响。例如:
- 修改用户级
~/.claude/CLAUDE.md(影响所有项目) - 修改用户级
~/.zshrc/~/.bashrc(影响所有终端会话) - 全局安装 npm 包(
npm install -g) - 修改系统级 hosts 文件、DNS 配置
这类动作 deny 规则较难枚举。应对策略:
- 默认让 Claude 在项目内工作(
cwd限制) - 任何"路径在项目外"的动作都升级到 Plan 模式
- 用 Hooks 检测路径,拦截 cross-project 操作
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write|Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$TOOL_INPUT\" | grep -qE '~/|/Users/[^/]+/|/home/[^/]+/' && ! echo \"$TOOL_INPUT\" | grep -q \"$(pwd)\"; then echo 'BLOCKED: 检测到对项目外路径的操作,请使用 plan 模式确认' >&2; exit 1; fi"
}
]
}
]
}
}
四、信任分级——什么时候让 AI 自动决策
4.1 不可逆 vs 可逆动作的区分
权限设计的第一性原理:可逆动作放宽,不可逆动作收紧。
- 可逆:写代码、跑测试、生成文档。错了
git checkout就回去了。 - 不可逆:发邮件、推送代码、删除分支、扣用户款。错了无法撤回。
这条标准看似简单,但很多反模式都源于"误以为可逆其实不可逆"——例如以为"git push 错了再 push 一次",实际上 main 分支被 force-push 后中间的 commit 可能已经被其他人 pull 过、引发协作灾难。判断"可逆"时要问的不是"我能不能撤回",而是"撤回时其他人是否已经基于错误状态做了进一步动作"。
4.2 影响半径
| 影响半径 | 例子 | 推荐权限层级 |
|---|---|---|
| 单文件 | 修改一个 source file | 执行层(自动) |
| 单仓库 | 修改 package.json、tsconfig | 审查层(Plan) |
| 单项目 | 部署到 staging | 审查层 + 人工确认 |
| 全公司 | 修改共享库、共享 CI | 决策层(人类原创) |
| 全用户 | 部署到生产、广告投放 | 决策层(人类原创) |
影响半径越大,权限要求越严。这条标准比"AI 是否擅长"重要——哪怕 AI 在某个领域已经远超人类,影响半径大的动作依然必须由人类拍板,因为责任归属不容混淆。
4.3 自动化决策的"四象限"模型
把"可逆性 × 影响半径"组合成四象限:
影响大
│
│ 慎重(人类决策) ┃ 绝不(人类原创)
│ ┃
──┼──────────────────╋──────────────────
│ ┃
│ 自动(AI 执行) ┃ Plan(AI 提议)
│ ┃
└─────────────────────────────────── 不可逆
影响小
- 左下(可逆 + 影响小):放心交给 AI,例如修改单个函数
- 左上(不可逆 + 影响小):让 AI 提议,人类点击批准(例如 git commit)
- 右下(可逆 + 影响大):让 AI 提议 plan,人类审阅(例如重构跨 10 个文件)
- 右上(不可逆 + 影响大):人类原创决策(例如生产部署、删除用户数据)
4.4 团队的"信任曲线"
信任不是一蹴而就,而是随时间逐步建立。一份合理的"信任曲线"可能是:
| 团队阶段 | 默认权限模式 | 可放权动作 |
|---|---|---|
| 第 1 周 | plan(强制审批) | 仅 Read、跑 lint |
| 第 1 个月 | default | + Edit、写测试 |
| 第 3 个月 | acceptEdits | + git commit (本地)、跑 build |
| 第 6 个月 | acceptEdits + 完善的 Hooks | + 提 PR、更新依赖(dev) |
| 长期稳定 | acceptEdits + 严格 deny | 仅生产/密钥/迁移仍人工 |
信任曲线必须基于真实使用观察:每周记录一次"AI 出错事件"——如果错误率持续下降,可以放权;如果某类错误反复出现,应当在该方向加强 deny 或 Hooks。
信任曲线的"四类信号":判断是否可以进入下一阶段时,重点观察:
- 零事故周数:连续 4 周以上无 AI 误操作事故,可以考虑放权。
- AI 误操作的可逆程度:如果偶发误操作都属于"易回滚"类,说明现有边界够用;如果出现过"差点不可逆"的事件,应该收紧。
- 工程师手动确认率:如果 80% 以上的确认都被点了"批准",说明确认门槛过低、工程师麻木了,需要把这部分动作放进白名单减少疲劳。
- 新人上手速度:新工程师能否在 1 周内理解并遵守现有权限边界?如果不能,说明边界设计太复杂,需要简化。
四个信号每月评估一次。评估的"上下两个方向"都要考虑——既要识别"应该放权"的信号,也要识别"应该收紧"的信号。很多团队只盯着前者,最终导致权限失控。
4.5 信任不能跨场景迁移
重要警示:在 A 项目建立的信任,不等于在 B 项目可以同等放权。原因:
- 不同项目的 CLAUDE.md / Skills 不同,Claude 对项目惯例的把握程度不同
- 不同项目的代码复杂度不同,AI 出错的概率不同
- 不同项目的业务敏感度不同,错误的代价不同
新项目接入 Claude Code 时,应当回到最严格的 plan 模式重新走一遍信任曲线。这个"重置"可能让人觉得繁琐,但它是避免"凭习惯放权导致大事故"的最直接保护。
跨场景迁移的"两不带原则":
- 不带 settings.json:每个项目的 settings.json 独立维护,不要从老项目复制粘贴。复制粘贴会带来"这条规则当年是为什么加的"的失忆症。
- 不带 Skills:Skills 也按项目独立。可以在团队层面维护"通用 Skills 模板库",每次新项目从模板库选择性引入,但禁止整套打包带走——每个项目的需求差异远大于复用收益。
只有**CLAUDE.md 中的"原则性内容"**可以跨项目复用,例如"密钥不进 prompt"、"生产 migration 不自动执行"这类与具体业务无关的安全铁律。具体实现细节、白名单、Hooks 路径等都应该在新项目中重新评估、重新设计。
五、安全反模式与防御
5.1 让 AI 直接读 .env / 生产配置
反模式:调试 API 调用时方便起见,让 Claude 读 .env 拿 API_KEY。
后果:API_KEY 进入 Claude 的会话上下文,理论上会被存进训练数据采样池(哪怕概率极低);更糟的是,工程师后续可能把会话内容复制粘贴到日志、bug 报告、Slack 中——密钥就这样扩散了。
防御:deny 规则硬阻断 .env 读写;调试时用 <API_KEY> 占位符让 Claude 帮你写代码,由你本地手动注入真实值再跑。
真实事故案例(脱敏):某团队工程师为了快速调试一个 Stripe 支付问题,把整段含 Authorization: Bearer sk_live_xxx 的失败请求粘贴到 Claude 会话。事后该工程师把会话日志保存到内部知识库分享给同事,知识库被一个新入职但还未完成保密协议培训的实习生看到。事故发现后,团队不得不轮换 Stripe 密钥、重新审计过去 30 天的 API 调用日志、向合规团队报备。整个事故的"根因"是一次毫无恶意的复制粘贴——但现代密钥的扩散链路就是这么短、这么不起眼。
事故复盘后,该团队把以下三条加入 CLAUDE.md:
## 密钥处理规则(来自 2026-01-23 P2 事故)
- 调试时遇到含密钥的请求/响应,**先脱敏再贴**,绝不带入会话
- 团队 Skill `.claude/skills/sanitize-log/` 提供一键脱敏脚本,必须使用
- 任何会话日志需要保留时,必须再次脱敏后归档,不得直接贴入 wiki/Slack
这三条规则配合 deny 规则,形成"工具阻断 + 行为规范 + 审计回溯"三层防御。
5.2 把 API Key 粘贴到 prompt 中调试
反模式:复制一段调用日志(含 Authorization Header)粘贴给 Claude 让它分析。
后果:与上一条相同——密钥扩散。
防御:粘贴前手动脱敏。建议团队配一个 .claude/skills/sanitize-log/ 的 skill,自动用 sed 替换常见的 token 字段:
# .claude/skills/sanitize-log/sanitize.sh
sed -E '
s/(Authorization:\s*Bearer\s+)[A-Za-z0-9._-]+/\1<REDACTED>/gi
s/(api[_-]?key["'"'"':=\s]+)[A-Za-z0-9_-]+/\1<REDACTED>/gi
s/(password["'"'"':=\s]+)[^"'"'"',\s]+/\1<REDACTED>/gi
s/(token["'"'"':=\s]+)[A-Za-z0-9._-]+/\1<REDACTED>/gi
'
工程师贴日志前先 pbpaste | bash sanitize.sh | pbcopy,再贴给 Claude。
5.3 给 Claude bypassPermissions 后忘记关
反模式:为了一次"快速跑"开了 bypassPermissions,事情忙完忘记关,下次 Claude 直接静默执行了高风险动作。
防御:
- 把
bypassPermissions启用挂上 SessionEnd 提醒——每次会话结束时打印"⚠️ 你目前在 bypassPermissions 模式,下次启动请确认"。 - 启动 Claude 时显示当前权限模式 banner——一眼能看到自己在哪个模式。
- 团队规定:任何在生产相关项目使用
bypassPermissions的动作必须 1on1 报备。规则可能不会被严格执行,但它能让"开 bypass"变成一个心理上需要犹豫的动作。
5.4 hooks 失败被静默吞掉
反模式:Hook 脚本因为 command not found 或 permission denied 静默失败,工程师以为"hook 在保护我",实际上没有。
防御:
- Hook 脚本必须有明确的错误处理——失败时输出可读 stderr。
- 定期运行
claude --check-hooks或自定义验证脚本,确认 hooks 都活着。 - 不要把"hooks 失败"等同于"放行"——某些场景应该是"hooks 失败时禁止动作"。
Hook 健康度自检脚本:写一个简单的 self-test,每周自动跑一次,验证所有 Hook 是否正常工作:
#!/bin/bash
# .claude/hooks/self-test.sh
# 每周一 9 点通过 cron 跑一次
set -e
echo "## Hooks Self-Test — $(date)"
# 测试 secret 检测 hook
echo "test_key=sk_live_abcdef123456" > /tmp/hook-test.txt
if node .claude/hooks/check-secret-leak.js "/tmp/hook-test.txt" 2>/dev/null; then
echo "❌ FAIL: secret leak hook didn't catch obvious test pattern"
exit 1
else
echo "✅ PASS: secret leak hook works"
fi
# 测试大文件检测 hook
dd if=/dev/zero of=/tmp/big-file.bin bs=1M count=10 2>/dev/null
if node .claude/hooks/check-big-file.js "/tmp/big-file.bin" 2>/dev/null; then
echo "❌ FAIL: big file hook didn't catch 10MB file"
exit 1
else
echo "✅ PASS: big file hook works"
fi
rm -f /tmp/hook-test.txt /tmp/big-file.bin
echo "All hooks healthy."
如果 self-test 失败,立即报警(Slack / PagerDuty / 邮件)。不要让工程师"误以为 hooks 在保护"——验证一次胜过假设一百次。
5.5 Skills 中嵌入未验证的外部脚本
反模式:从网上 copy 一段 curl xxx | sh 的安装脚本塞进 Skill,每次 Skill 执行时都跑一遍。
后果:远端脚本被劫持时,Skill 的每次运行都会执行恶意代码。
防御:
- Skills 中的所有外部下载必须 pin 到具体版本 / 哈希。
- Skills 一旦稳定就 pin 住——不要让它"自动获取最新版本"。
- 团队 Skill 库定期 audit,把所有外部依赖列出来评估风险。
Skill 安全审计的"三步法":
- 静态扫描:写一份 audit 脚本,扫描所有
.claude/skills/**/*.{sh,js,py}中的外部 URL、curl 命令、wget 命令、远端 import。把结果输出到.claude/skills-audit.md。 - 依赖图谱:让 Claude 协助生成"Skill 依赖图谱"——哪些 Skill 调用哪些外部资源、哪些 Skill 又调用其他 Skill。当一个外部资源被多个 Skill 共享时,它的安全等级应该相应提高。
- 季度 audit 会议:每季度一次专门的"Skills 安全 audit 会",团队一起 review 当前 Skills 库,淘汰过时 Skill、收紧依赖、更新版本。
让 Claude 协助起草 audit 脚本:
#!/bin/bash
# .claude/scripts/skills-audit.sh
echo "## Skills 外部依赖 audit — $(date)"
echo
for skill in .claude/skills/*/; do
echo "### $(basename "$skill")"
echo
# 扫描 curl / wget / npm install 等外部下载
grep -rE 'curl |wget |npm install |pip install |go get ' "$skill" 2>/dev/null | sed 's/^/ /'
echo
done
跑一次脚本就能拿到当前 Skills 库的"对外依赖清单",作为 audit 会议的输入。
六、PM 与工程师的安全边界差异
6.1 PM 视角:定义"哪些功能/数据是敏感的"
PM 不需要懂 settings.json,但必须能回答:
- 哪些用户数据属于"绝不能泄漏"(密码、支付信息、隐私设置)
- 哪些功能属于"必须人工二次确认"(删除账户、转账、批量操作)
- 哪些场景的故障会触发法律/合规风险(GDPR、个保法、PCI-DSS)
PM 把这些约束转化为"业务级安全清单",工程师再翻译为 deny 规则与 Hooks。
PM 安全清单的"四象限"模板:PM 可以用一个简单的二维表格梳理业务安全敏感点——
| 可逆 | 不可逆 | |
|---|---|---|
| 影响小 | 普通配置修改 | 一次性发送的内部通知 |
| 影响大 | 全员功能开关 | 删除用户账户、转账、批量发送营销邮件 |
每个象限的处理建议:
- 左上(可逆 + 影响小):放心交给 AI 协助开发,普通流程即可
- 左下(可逆 + 影响大):开发可由 AI 协助,生产开关切换需人工
- 右上(不可逆 + 影响小):开发由 AI 协助,触发条件需人工二次确认
- 右下(不可逆 + 影响大):开发可由 AI 协助,但所有触发链路需多重确认 + 操作日志 + 撤销窗口
PM 把这份四象限按业务功能逐个填空,工程师拿到后翻译成对应的代码层防护:
- 多重确认 → 二次密码确认 / 短信验证 / 邮件确认链接
- 操作日志 → 审计表(audit log)+ 监控告警
- 撤销窗口 → "30 天可恢复"机制(如删除账户的"软删除"模式)
6.2 工程师视角:把 PM 定义的敏感性翻译为 deny 规则
工程师收到 PM 清单后,需要:
- 找到对应代码路径(例如"用户密码"对应
src/auth/password.ts) - 加入 deny 列表(
Edit(src/auth/**)进 plan 模式) - 配置 Hooks 监控(任何对该路径的写操作都跑额外 lint + 强制 review)
- 在 CLAUDE.md 里说明"为什么这块敏感"
翻译过程中的常见失真:PM 的语言("用户隐私"、"支付信息")与工程师的语言("数据库表"、"代码路径")之间存在天然鸿沟。常见失真包括——PM 说"保护用户密码",工程师只锁了 src/auth/password.ts,但忘了 src/auth/reset-password.ts、src/auth/oauth-callback.ts、src/admin/users.ts 等周边文件也可能触及密码逻辑。翻译时建议工程师与 PM 一起做一次"路径走读"——PM 描述用户场景,工程师同步指出场景涉及的所有代码路径,确保 deny 规则覆盖完整的"风险面"而非"风险点"。
6.3 跨角色协作:合规审查与代码审查的协同
合规审查与代码审查不应分割。建议每月一次"安全清单同步会":
- PM 列出本月的新业务/新风险
- 工程师列出本月的新 deny 规则与 Hooks 改动
- 双方对照"业务需要保护的 vs 实际配置保护的"
- 找出 gap,下个月补齐
同步会的"五个固定议题":
- 新功能/新接口的安全等级评估——本月上线的功能里,哪些涉及敏感数据?哪些有人工二次确认机制?哪些有审计日志?
- 本月 AI 出错事件回顾——
.claude/incidents.md里新增了哪些事件?根因是什么?是否需要更新 deny 规则? - deny 规则覆盖度核查——业务清单上的"敏感"项是否都在 settings.json 里有对应保护?
- 法规变更追踪——本月有没有新的合规要求(GDPR 解读更新、个保法实施细则、行业标准修订)?是否需要调整流程?
- 同步会本身的 review——上次会议的 action item 完成了多少?拖延的原因是什么?
每月会议留下书面纪要,归档到 .claude/security-meetings/YYYY-MM.md。半年累积下来,这些会议纪要本身就是团队"安全成熟度"的最佳量化指标——通过翻阅历次纪要,新人能快速理解团队过去面对过哪些风险、做出过哪些决策、为什么形成现在这套规则。
6.4 团队级"安全行为公约"
把这一节的所有原则浓缩为一份团队公约,贴在 wiki 第一页:
## 团队 Claude Code 安全公约(v1.0)
1. 生产相关项目永不开 `bypassPermissions`
2. `.env` / secrets / credentials 文件 Claude 不读、不写、不引用
3. prompt 中粘贴日志前必须脱敏
4. git push / kubectl apply / pnpm publish 永远手动确认
5. 数据库 migration Claude 只生成、不执行
6. 新项目从 plan 模式起步,逐步建立信任
7. 任何 AI 出错事件必须记入 .claude/incidents.md
8. 每月一次安全清单同步会,全员参与
签字:工程团队全员、产品团队全员
日期:[填写]
公约不是装饰,而是强制规则。新人入职第一天读、每月会议引用、年度审查更新。这一份公约的存在,往往比一万行 settings.json 更能塑造团队的安全文化。
公约维护的"三大原则":
- 不要过度膨胀。8-12 条是公约的健康长度,超过 20 条意味着没人会真的读完。如果某条原则已经被工具自动化(例如 deny 列表),可以从公约中移除——公约只保留"工具无法 100% 强制、需要团队自觉"的部分。
- 每条公约都要有"为什么"。每条原则后面挂一段 50-200 字的"背景注释",解释这条规则的来源(来自哪次事故、哪条法规、哪种风险)。规则的"知其所以然"才能让规则在压力情境下被遵守。
- 每年一次"公约 review"。技术栈变了、业务变了、风险也会变。一份去年还有效的公约,今年可能已经成为团队效率的负担。把每年一月作为公约 review 月,全员参与重新签字——这一仪式本身就是文化的更新。
安全文化的最终衡量:一个团队的安全文化是否健康,不取决于 settings.json 多严密、Hooks 多复杂,而取决于一个简单的问题——"团队成员遇到不确定动作时,是默认前进还是默认询问?"。前者称为"风险偏好型文化",后者称为"风险规避型文化"。AI 协作时代的工程团队应当坚定地选择后者——因为 AI 能放大团队的效率,也能放大团队的错误。当工具变得越来越强大时,"默认询问"的文化是把"放大错误"的尾部风险压在可接受范围内的最后一道防线。
总结
权限边界不是用来限制 AI 的,而是用来保护人类——保护工程师不在疲劳时做错决定、保护团队不被某次失误拖垮、保护用户不被未经审查的代码影响、保护组织不被一次外部攻击撕裂。本节给出的"权限三层模型 + Claude Code 机制 + 五类高风险动作 + 信任曲线 + 反模式 + 团队公约"组成了一套完整的防御体系,目标只有一个——让"AI 协作"在解放生产力的同时,不让责任链断裂。
最重要的一条心法:当你犹豫"这个动作是否可以让 Claude 自动执行"时,默认选择"不行"。安全设计的代价是工程师每天多按几次"批准"按钮(成本:每次 2 秒);安全设计失败的代价是某天某次的灾难性事故(成本:可能数小时到数月恢复时间 + 信任损失 + 可能的法律责任与商业赔付)。两者之间的赔率比悬殊到惊人,永远站在保守的一侧不会错。这条心法听起来朴素,但它是把"防御纵深"思想内化为肌肉记忆的最直接路径。任何一个能在压力情境下默认问一句"我是不是该再次确认一下"的工程师,都已经走在了团队安全文化的正确道路上,而这种朴素的谨慎会随着时间持续产生显著的复利效应。
下一节 7.4 将进入"心法层"的最后一节——Boris Cherny 的 9 条实战心法。这 9 条心法是 Anthropic Claude Code 团队在多个真实项目中沉淀出的精华,与本节的安全边界形成互补:本节告诉你"不要做什么",下一节告诉你"做对的事"。
留给读者的两个习题:
- 在你当前项目里写一份
.claude/settings.json的 deny 列表,至少包含 10 条规则。每条规则配一行说明"为什么禁止"。 - 与团队对齐一份"团队 Claude Code 安全公约",至少包含 5 条原则。让所有 PM 与工程师签字,贴在团队 wiki 第一页。
这两个习题做完,你会发现"安全"不再是抽象的合规要求,而是被结构化嵌入工作流的具体动作。
额外建议:把这两份文档放在团队 onboarding 流程的"必读"清单里。新人入职第一天就读、第一周做小测验。这样做的目的不是考核,而是让新人在最容易接受规则的窗口期,把安全文化内化为本能反应。半年后这位新人变成 senior,他会自然而然地把这套思维方式传递给下一批新人——这是文化传承最稳定的路径。安全文化从来不是"靠制度强压",而是"靠每一代工程师的言传身教"。Claude Code 的工具与文档可以加速这一传承过程,但不能替代它。
延伸阅读
- Anthropic Claude Code 官方文档 — Permission Mode、Hooks、settings.json 全览
- Anthropic: Responsible Scaling Policy — 负责任 AI 部署的官方框架
- OWASP Top 10 — Web 安全经典威胁清单
- OWASP LLM Top 10 — LLM 应用专属安全威胁清单
- Google SRE Book — Security — Google SRE 实践中的安全章节
- The Twelve-Factor App — Config — 配置与密钥分离的经典原则
- Trusted Types W3C 规范 — 浏览器端的可信类型规范,避免 DOM 注入
- Snyk: Supply Chain Security Best Practices — 供应链攻击防御实践
- GitHub: Best practices for keeping your supply chain secure — GitHub 官方供应链安全指南
- PyPI typo-squatting: Recent attack examples — 真实供应链攻击案例
- Charity Majors: Operational Maturity Levels — Honeycomb 创始人对运维成熟度的分层模型
- Anthropic Trust & Safety — Anthropic 信任与安全文档中心