安全最佳实践
全面掌握 Claude Code 的安全机制 — 权限控制、敏感文件保护、命令拦截、API Key 管理
安全最佳实践¶
Claude Code 是一个强大的 AI 编程助手,但"强大"也意味着它需要较高的系统权限 — 读写文件、执行命令、访问网络。这就像给一个实习生配了管理员账号:能力很强,但必须有合适的安全边界。
这篇文档将帮助你建立全面的安全防线,从个人使用到团队协作,从开发环境到 CI/CD 自动化,确保你在享受 AI 编程效率的同时,不会踩到安全的坑。
理解 Claude Code 的安全模型¶
Claude Code 在你的终端中运行¶
这一点至关重要,也是理解所有安全措施的基础:Claude Code 不是运行在云端的沙箱里,而是直接运行在你的本地终端中。
这意味着:
- 它能读取你机器上的任何文件(只要你的用户有权限)
- 它能执行任何 Shell 命令
- 它能访问你的环境变量(包括里面可能存在的密钥)
- 它能通过网络发送和接收数据
当然,Claude Code 有内置的安全机制来约束这些能力。但你应该始终记住这个基本事实:它的权限上限就是你的用户权限。
权限审批机制¶
Claude Code 的核心安全理念是人在回路中(Human in the Loop)。默认情况下,它在执行以下操作时会请求你的确认:
- 第一次使用某个工具
- 执行 Shell 命令(特别是你没有预先批准的)
- 写入新文件或修改现有文件
- 访问网络资源
你看到的权限请求大致是这样的:
Claude wants to run: rm -rf node_modules && npm install
Allow?
(y) Yes, allow once
(a) Always allow "npm install" commands
(n) No, deny
关键原则:如果你不确定某个操作是否安全,选"No"。你总是可以在了解清楚后再批准。
三道防线¶
Claude Code 的安全体系由三道防线组成:
第一道:权限模式(全局策略)
↓
第二道:Allow/Deny 规则(精细控制)
↓
第三道:Hooks(自定义拦截逻辑)
下面我们逐一展开。
权限配置¶
四种权限模式对比¶
Claude Code 提供四种权限模式,安全级别从高到低排列:
| 模式 | 文件编辑 | 命令执行 | 适用场景 | 安全级别 |
|---|---|---|---|---|
plan |
禁止 | 禁止(仅只读) | 代码审查、架构分析 | 最高 |
default |
首次询问 | 每次询问 | 日常开发 | 高 |
acceptEdits |
自动批准 | 每次询问 | 频繁修改文件的任务 | 中 |
bypassPermissions |
自动批准 | 自动批准 | CI/CD、受信任环境 | 低 |
各模式详解:
plan 模式:Claude 只能搜索和阅读代码,不能做任何修改。适合你想让 Claude 分析代码但不希望它动任何东西的场景。通过 Shift+Tab 切换到此模式。
default 模式:推荐的日常模式。Claude 第一次使用某类工具时会询问,你批准后同类操作不再重复询问。Shell 命令每次都会询问。
acceptEdits 模式:信任 Claude 的文件编辑能力,但对命令执行保持警惕。适合你需要 Claude 大量修改代码文件,但不希望它随意执行命令的场景。
bypassPermissions 模式:跳过所有权限检查。只在你完全信任当前任务、或者在隔离的 CI/CD 环境中使用。
通过 /permissions 查看和修改¶
在 Claude Code 中随时输入 /permissions 可以查看当前的权限状态:
/permissions
输出会显示当前模式、已批准的工具、Allow/Deny 规则等。
settings.json 中的权限配置¶
权限配置存储在 settings.json 中,分为两个级别:
用户级(影响所有项目):~/.claude/settings.json
项目级(仅影响当前项目):.claude/settings.json
{
"permissions": {
"defaultMode": "default",
"allow": [
"Bash(npm run lint)",
"Bash(npm run test:*)",
"Bash(git status)",
"Bash(git add:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(node:*)",
"Bash(python:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(git push --force:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Read(.env)",
"Read(.env.*)",
"Read(secrets/**)"
]
}
}
规则语法说明:
| 语法 | 含义 | 示例 |
|---|---|---|
Bash(cmd) |
精确匹配命令 | Bash(npm run lint) |
Bash(cmd:*) |
匹配命令前缀 | Bash(git log:*) 匹配所有 git log 开头的命令 |
Read(path) |
匹配文件读取 | Read(.env) |
Write(path) |
匹配文件写入 | Write(src/**) |
** |
多层目录通配 | Read(secrets/**) 匹配 secrets 下所有层级的文件 |
* |
单层通配 | Read(.env.*) 匹配 .env.local、.env.production 等 |
重要:Deny 规则的优先级高于 Allow 规则。即使你在 Allow 中批准了某个操作,如果它同时匹配了 Deny 规则,仍然会被拒绝。
敏感文件保护¶
使用 .claudeignore 排除敏感目录¶
.claudeignore 文件的语法与 .gitignore 相同,被列入的文件和目录对 Claude Code 完全不可见:
在项目根目录创建 .claudeignore:
# 环境变量和密钥
.env
.env.*
secrets/
*.pem
*.key
*credentials*
# 敏感配置
config/production.yml
config/secrets.yml
# 个人数据
data/users/
*.sqlite
*.db
# 其他敏感目录
.aws/
.ssh/
.gnupg/
注意:.claudeignore 让 Claude 完全看不到这些文件 — 它甚至不知道这些文件存在。这比 Deny 规则更彻底。
使用 Hooks 拦截对敏感文件的修改¶
如果你希望 Claude 能读取某些文件但不能修改,可以用 Hooks 来实现精细控制:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "python3 -c \"\nimport sys, json, os\ntool_input = json.loads(os.environ.get('TOOL_INPUT', '{}'))\npath = tool_input.get('file_path', '') or tool_input.get('path', '')\nprotected = ['.env', 'credentials', 'secret', '.pem', '.key']\nfor p in protected:\n if p in path.lower():\n print(f'BLOCKED: 不允许修改包含 {p} 的文件', file=sys.stderr)\n sys.exit(2)\n\""
}
]
}
]
}
}
这个 Hook 会在 Claude 尝试写入或编辑文件之前检查文件路径,如果路径中包含敏感关键词,就阻止操作(exit code 2 表示阻断)。
保护配置模板¶
对于团队项目,建议创建一个标准的安全配置文件,存放在仓库中:
// .claude/settings.json(提交到 Git)
{
"permissions": {
"deny": [
"Read(.env)",
"Read(.env.*)",
"Read(secrets/**)",
"Read(**/*.pem)",
"Read(**/*.key)",
"Write(.git/**)",
"Bash(rm -rf:*)",
"Bash(git push --force:*)",
"Bash(git reset --hard:*)",
"Bash(chmod 777:*)",
"Bash(curl|wget:*)"
]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo \"$TOOL_INPUT\" | python3 -c \"import sys,json; cmd=json.load(sys.stdin).get('command',''); blocked=['DROP TABLE','DELETE FROM','TRUNCATE','password','token','secret']; [sys.exit(2) for b in blocked if b.lower() in cmd.lower()]\""
}
]
}
]
}
}
命令执行安全¶
理解 Bash 工具的行为¶
Claude Code 通过 Bash 工具执行 Shell 命令。默认情况下,除了你预先批准的命令外,每次执行都需要你确认。
一些需要注意的行为:
- 命令在你当前的 Shell 环境中执行
- 环境变量对命令可见
- 命令可以修改文件系统
- 命令可以安装软件
- 命令可以访问网络
哪些命令会被自动审批¶
当你在 settings.json 的 allow 列表中添加了某个命令模式后,匹配的命令会自动执行,不再询问。
建议预批准的安全命令:
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(git branch:*)",
"Bash(ls:*)",
"Bash(cat:*)",
"Bash(head:*)",
"Bash(tail:*)",
"Bash(wc:*)",
"Bash(find:*)",
"Bash(grep:*)",
"Bash(npm run lint:*)",
"Bash(npm run test:*)",
"Bash(python -m pytest:*)"
]
}
}
危险命令拦截¶
以下命令应该始终放在 Deny 列表中,永远不允许自动执行:
{
"permissions": {
"deny": [
"Bash(rm -rf:*)",
"Bash(rm -r /:*)",
"Bash(git push --force:*)",
"Bash(git push -f:*)",
"Bash(git reset --hard:*)",
"Bash(git checkout -- .:*)",
"Bash(git clean -f:*)",
"Bash(chmod 777:*)",
"Bash(chown:*)",
"Bash(dd:*)",
"Bash(mkfs:*)",
"Bash(shutdown:*)",
"Bash(reboot:*)"
]
}
}
通过 Hooks 自定义命令拦截¶
对于更复杂的拦截逻辑,使用 Hooks:
示例 1:阻止所有网络请求命令
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo \"$TOOL_INPUT\" | python3 -c \"\nimport sys, json\ncmd = json.load(sys.stdin).get('command', '')\nnet_cmds = ['curl', 'wget', 'nc ', 'netcat', 'ssh ', 'scp ', 'rsync']\nfor nc in net_cmds:\n if nc in cmd:\n print(f'BLOCKED: 不允许执行网络命令 ({nc})', file=sys.stderr)\n sys.exit(2)\n\""
}
]
}
]
}
}
示例 2:记录所有命令到审计日志
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo \"$(date '+%Y-%m-%d %H:%M:%S') [Bash] $TOOL_INPUT\" >> ~/.claude/audit.log"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "echo \"$(date '+%Y-%m-%d %H:%M:%S') [FileChange] $TOOL_INPUT\" >> ~/.claude/audit.log"
}
]
}
]
}
}
这样你就有了一份完整的操作审计日志,可以随时回溯 Claude Code 做了什么。
API Key 安全¶
不要在 CLAUDE.md 中硬编码 API Key¶
这是最常见的安全错误。CLAUDE.md 文件通常会提交到 Git 仓库,而且 Claude Code 在每次启动时都会读取它。如果里面包含 API Key,那么:
- Key 会被提交到 Git 历史中(即使后来删除了)
- Key 对 Claude Code 可见,可能出现在日志或分析结果中
- 团队其他成员都能看到这个 Key
错误做法:
<!-- CLAUDE.md -->
## API 配置
数据库连接:postgresql://admin:P@ssw0rd@localhost:5432/mydb
OpenAI Key:sk-xxxxxxxxxxxxxxxxxxxx
正确做法:
<!-- CLAUDE.md -->
## API 配置
- 数据库连接和 API Key 通过 .env 文件管理
- .env 文件不提交到 Git(已在 .gitignore 中)
- 新开发者需要复制 .env.example 并填入自己的凭据
使用环境变量管理密钥¶
推荐的密钥管理方式:
# .env(不提交到 Git)
DATABASE_URL=postgresql://admin:P@ssw0rd@localhost:5432/mydb
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxx
REDIS_URL=redis://localhost:6379
# .env.example(提交到 Git,不含实际值)
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
OPENAI_API_KEY=sk-your-key-here
REDIS_URL=redis://localhost:6379
确保 .env 在 .gitignore 和 .claudeignore 中:
# .gitignore
.env
.env.local
.env.production
# .claudeignore(如果你不希望 Claude 读取 .env)
.env
.env.*
API Key 泄露后的处理步骤¶
如果你怀疑 API Key 已经泄露(比如不小心提交到了 Git),请立即执行以下步骤:
1. 立即轮换密钥
- 到对应服务的控制台生成新的 API Key
- 更新所有使用该 Key 的环境变量
2. 从 Git 历史中移除
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch .env" \
--prune-empty --tag-name-filter cat -- --all
或使用更安全的 BFG Repo-Cleaner:
bfg --delete-files .env
git reflog expire --expire=now --all
git gc --prune=now --aggressive
3. 强制推送清理后的历史
git push --force --all
4. 检查异常使用
- 查看 API 使用日志,检查是否有异常调用
- 检查计费记录,看是否有异常消费
5. 通知团队
- 告知所有开发者重新克隆仓库
- 更新所有部署环境的密钥
团队安全规范¶
共享 settings.json 模板¶
为团队创建统一的安全基线配置,提交到项目仓库的 .claude/settings.json:
{
"permissions": {
"defaultMode": "default",
"allow": [
"Bash(npm run:*)",
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(python -m pytest:*)"
],
"deny": [
"Read(.env)",
"Read(.env.*)",
"Read(secrets/**)",
"Read(**/*.pem)",
"Read(**/*.key)",
"Read(**/*credential*)",
"Write(.git/**)",
"Bash(rm -rf:*)",
"Bash(git push --force:*)",
"Bash(git reset --hard:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(ssh:*)",
"Bash(scp:*)"
]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo \"$(date -Iseconds) TOOL_USE: $TOOL_INPUT\" >> .claude/audit.log"
}
]
}
]
}
}
团队成员可以在 ~/.claude/settings.json(用户级)中添加个人配置,但项目级的 Deny 规则不可被覆盖。
CI/CD 中的安全配置¶
在 CI/CD 环境中使用 Claude Code(Headless 模式)时,安全配置更为重要:
# GitHub Actions 示例
name: AI Code Review
on: [pull_request]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Claude Code Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
claude --print --dangerously-skip-permissions \
"请审查本次 PR 的代码变更,给出安全性和代码质量的评价" \
< /dev/null
CI/CD 安全注意事项:
| 注意项 | 说明 |
|---|---|
| API Key 管理 | 使用 CI/CD 平台的 Secrets 管理(如 GitHub Secrets),不要硬编码 |
| 权限最小化 | CI 环境中的 Claude Code 应该只有只读权限,不应修改代码 |
| 网络隔离 | 限制 CI 环境的出站网络访问 |
| 超时设置 | 设置合理的执行时间上限,防止异常长时间运行 |
| 日志清理 | 确保 CI 日志中不包含敏感信息 |
Headless 模式安全注意事项¶
Headless 模式(--print 或 -p)用于非交互式场景,没有人在回路中确认操作。使用时需要格外注意:
# 安全的 Headless 用法 — 只读操作
claude --print "分析 src/ 目录的代码结构"
# 需要写操作时,限定具体文件
claude --print "修复 src/utils.py 中的类型错误"
# 使用 --dangerously-skip-permissions 时要明确知道风险
claude --print --dangerously-skip-permissions "运行 npm test"
--dangerously-skip-permissions 这个参数名字之所以这么长,就是为了提醒你:跳过权限检查是危险的。只在你完全控制输入提示词、完全了解可能的操作时才使用。
企业级安全¶
网络访问控制¶
如果你的企业有严格的网络安全策略,可以通过以下方式控制 Claude Code 的网络访问:
1. 代理配置
通过环境变量设置 HTTP 代理,所有网络请求都经过代理,方便审计和控制:
# 在 .bashrc 或 .zshrc 中设置
export HTTP_PROXY=http://proxy.company.com:8080
export HTTPS_PROXY=http://proxy.company.com:8080
export NO_PROXY=localhost,127.0.0.1,.company.com
2. 防火墙规则
在企业防火墙上,可以只允许 Claude Code 访问必要的域名:
# 必须允许的域名
api.anthropic.com # Anthropic API
*.claude.ai # Claude 服务
# 可选允许(根据使用的功能)
registry.npmjs.org # npm 包安装
pypi.org # Python 包安装
github.com # Git 操作
3. 在 settings.json 中禁止网络命令
作为额外的安全层,在 Deny 规则中禁止常见的网络工具:
{
"permissions": {
"deny": [
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(nc:*)",
"Bash(ssh:*)",
"Bash(scp:*)",
"Bash(rsync:*)",
"Bash(ftp:*)",
"Bash(telnet:*)"
]
}
}
日志审计¶
对于合规性要求较高的企业,建议建立完整的审计日志体系:
1. 操作日志
通过 Hooks 记录所有工具调用:
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "python3 -c \"\nimport json, os, datetime\nlog_entry = {\n 'timestamp': datetime.datetime.now().isoformat(),\n 'user': os.environ.get('USER', 'unknown'),\n 'tool': os.environ.get('TOOL_NAME', 'unknown'),\n 'input': os.environ.get('TOOL_INPUT', '')[:500]\n}\nwith open(os.path.expanduser('~/.claude/audit.jsonl'), 'a') as f:\n f.write(json.dumps(log_entry, ensure_ascii=False) + '\\n')\n\""
}
]
}
]
}
}
2. 会话日志
Claude Code 自身会保留会话历史,存储在 ~/.claude/ 目录下。企业可以定期备份这些日志。
3. 变更追踪
结合 Git,所有文件变更都有完整的追踪记录。建议 Claude Code 的每次修改都在独立分支上进行,通过 PR 流程合并。
合规性考虑¶
使用 AI 编程工具可能涉及以下合规问题:
数据安全
| 风险 | 应对措施 |
|---|---|
| 代码上传到云端 | Claude Code 不会上传你的代码到 Anthropic 服务器(除了 API 请求中的上下文) |
| 敏感数据泄露 | 使用 .claudeignore 排除敏感文件;在 Deny 规则中阻止读取 .env 和密钥文件 |
| API 请求中的敏感信息 | 避免在对话中粘贴密码、Token 等敏感信息 |
知识产权
- Claude Code 的输出(生成的代码)归使用者所有
- 注意检查 Claude 生成的代码是否包含受版权保护的内容
- 对于关键业务代码,建议人工审查后再使用
行业合规
- 金融、医疗等受监管行业可能有额外的 AI 使用限制
- 确认你的组织是否有关于 AI 工具的使用政策
- 保持审计日志以满足合规审查需求
安全配置速查表¶
最后,这里是一份快速参考的安全配置清单:
个人开发者最低安全配置¶
{
"permissions": {
"deny": [
"Read(.env)",
"Read(.env.*)",
"Bash(rm -rf:*)",
"Bash(git push --force:*)"
]
}
}
团队项目推荐配置¶
{
"permissions": {
"defaultMode": "default",
"allow": [
"Bash(npm run:*)",
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git log:*)"
],
"deny": [
"Read(.env)",
"Read(.env.*)",
"Read(secrets/**)",
"Read(**/*.pem)",
"Write(.git/**)",
"Bash(rm -rf:*)",
"Bash(git push --force:*)",
"Bash(git reset --hard:*)",
"Bash(curl:*)",
"Bash(wget:*)"
]
}
}
高安全企业配置¶
{
"permissions": {
"defaultMode": "default",
"allow": [
"Bash(npm run lint)",
"Bash(npm run test)",
"Bash(git status)",
"Bash(git diff)"
],
"deny": [
"Read(.env)",
"Read(.env.*)",
"Read(secrets/**)",
"Read(**/*.pem)",
"Read(**/*.key)",
"Read(**/*credential*)",
"Read(**/*password*)",
"Write(.git/**)",
"Write(.github/**)",
"Bash(rm:*)",
"Bash(git push:*)",
"Bash(git reset:*)",
"Bash(git checkout -- :*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Bash(ssh:*)",
"Bash(scp:*)",
"Bash(nc:*)",
"Bash(python -c:*)",
"Bash(node -e:*)",
"Bash(eval:*)",
"Bash(exec:*)",
"Bash(sudo:*)",
"Bash(chmod:*)",
"Bash(chown:*)"
]
},
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "python3 -c \"import json,os,datetime; f=open(os.path.expanduser('~/.claude/audit.jsonl'),'a'); f.write(json.dumps({'ts':datetime.datetime.now().isoformat(),'user':os.environ.get('USER','?'),'tool':os.environ.get('TOOL_NAME','?'),'input':os.environ.get('TOOL_INPUT','')[:500]},ensure_ascii=False)+'\\n'); f.close()\""
}
]
}
]
}
}
常见问题¶
Q:Claude Code 会把我的代码发送到 Anthropic 的服务器吗?
A:Claude Code 通过 API 与 Anthropic 通信,对话上下文(包括你引用的代码片段)会作为 API 请求的一部分发送。但 Anthropic 不会使用通过 API 提交的数据来训练模型(根据 Anthropic 的使用条款)。如果你通过 QCode 等中转服务使用,请参考该服务的隐私政策。
Q:settings.json 中的 Deny 规则能被 Claude 绕过吗?
A:在正常使用下不能。Deny 规则在系统层面强制执行,Claude 无法通过提示词工程或其他方式绕过。但如果你手动选择 bypassPermissions 模式或使用 --dangerously-skip-permissions 参数,这些规则就不再生效。
Q:.claudeignore 和 Deny 规则有什么区别?
A:.claudeignore 让 Claude 完全看不到文件的存在(类似 .gitignore 之于 Git),而 Deny 规则是在 Claude 试图访问时才拒绝。如果你不希望 Claude 知道某些文件的存在,用 .claudeignore;如果只是不想让它修改,用 Deny 规则。
Q:多人协作时,每个人的 settings.json 不同怎么办?
A:项目级的 .claude/settings.json 提交到 Git,确保团队共享统一的安全基线。个人的 ~/.claude/settings.json 中可以添加额外配置,但不能覆盖项目级的 Deny 规则。
Q:在 Docker 容器中使用 Claude Code 是否更安全?
A:是的。Docker 提供了额外的隔离层,即使 Claude Code 执行了意外的操作,影响也被限制在容器内。建议在容器中:使用只读挂载源代码目录、限制网络访问、使用非 root 用户运行。