为什么要关注安全
Claude Code 拥有强大的能力——它可以读写文件、执行 shell 命令、访问网络。这些能力在提升效率的同时,也带来了安全风险。
想象一下:
- 它不小心读取了
.env文件中的 API Key - 它执行了一个
rm -rf命令 - 它把敏感信息写进了 commit
这些都是真实可能发生的场景。所以我们需要一套完整的安全实践来防范。
权限模式
Claude Code 提供了三种权限模式来控制工具的执行:
| 模式 | 行为 | 适用场景 |
|---|---|---|
| ask | 每次执行前询问用户确认 | 默认模式,最安全 |
| auto-accept | 自动允许执行 | 信任的操作,提升效率 |
| deny | 禁止执行 | 危险操作,完全阻止 |
在 settings.json 中配置
{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep",
"Write(src/**)",
"Edit(src/**)",
"Bash(npm run lint)",
"Bash(npm run test)",
"Bash(npm run build)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(curl * | bash)",
"Write(.env*)",
"Write(*.pem)",
"Write(*.key)"
]
}
}
权限配置的粒度
权限可以精确到工具 + 参数级别:
{
"permissions": {
"allow": [
"Read",
"Write(src/**)",
"Write(tests/**)",
"Edit(src/**)",
"Edit(tests/**)",
"Bash(npm *)",
"Bash(npx *)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git add *)",
"Bash(git commit *)"
],
"deny": [
"Write(.*)",
"Write(*.env*)",
"Bash(git push --force*)",
"Bash(git reset --hard*)",
"Bash(rm -rf *)",
"Bash(sudo *)",
"Bash(chmod 777 *)"
]
}
}
权限优先级
当 allow 和 deny 冲突时,deny 优先:
{
"permissions": {
"allow": ["Write(src/**)"],
"deny": ["Write(src/config/secrets.ts)"]
}
}
即使允许写入 src/**,src/config/secrets.ts 仍然被禁止。
敏感文件保护
.gitignore 是第一道防线
确保敏感文件不会被 Git 追踪:
# 环境变量
.env
.env.local
.env.production
# 密钥文件
*.pem
*.key
*.p12
*.pfx
# 凭证
credentials.json
service-account.json
*-credentials.json
# IDE 和工具
.claude/settings.local.json
在 CLAUDE.md 中声明禁区
## 安全规则
### 禁止访问的文件
- `.env*` - 环境变量文件
- `*.pem`, `*.key` - 密钥文件
- `credentials.json` - 凭证文件
- `src/config/secrets.ts` - 密钥配置
### 禁止执行的操作
- 不要读取或输出任何 API Key、密码、Token
- 不要执行 `curl | bash` 类型的命令
- 不要修改文件权限(chmod)
- 不要使用 sudo
使用 .claudeignore
类似 .gitignore,.claudeignore 可以让 Claude Code 完全忽略某些文件:
# .claudeignore
.env
.env.*
*.pem
*.key
credentials/
secrets/
node_modules/
被 .claudeignore 忽略的文件,Claude Code 不会读取、不会在搜索结果中出现、也不会被修改。
网络访问控制
Claude Code 可以通过 WebFetch 工具访问网络。在某些环境中,我们需要限制这个能力:
禁止网络访问
{
"permissions": {
"deny": [
"WebFetch"
]
}
}
限制访问域名
在 Hook 中实现域名白名单:
#!/bin/bash
# .claude/hooks/check-url.sh
INPUT="$CLAUDE_TOOL_INPUT"
URL=$(echo "$INPUT" | jq -r '.url // empty')
# 域名白名单
ALLOWED_DOMAINS=(
"github.com"
"npmjs.com"
"developer.mozilla.org"
"docs.astro.build"
)
if [ -n "$URL" ]; then
DOMAIN=$(echo "$URL" | awk -F/ '{print $3}')
ALLOWED=false
for d in "${ALLOWED_DOMAINS[@]}"; do
if [[ "$DOMAIN" == *"$d"* ]]; then
ALLOWED=true
break
fi
done
if [ "$ALLOWED" = false ]; then
echo "BLOCKED: 不允许访问域名 $DOMAIN"
exit 1
fi
fi
{
"hooks": {
"PreToolUse": [
{
"matcher": "WebFetch",
"hook": {
"type": "command",
"command": "bash .claude/hooks/check-url.sh"
}
}
]
}
}
审计日志
记录 Claude Code 的所有操作,便于事后审查:
基础审计日志
#!/bin/bash
# .claude/hooks/audit-log.sh
LOG_DIR=".claude/logs"
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/audit-$(date +%Y%m%d).log"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
TOOL="$CLAUDE_TOOL_NAME"
SESSION="$CLAUDE_SESSION_ID"
echo "[$TIMESTAMP] session=$SESSION tool=$TOOL" >> "$LOG_FILE"
# 记录文件操作
if [ -n "$CLAUDE_FILE_PATH" ]; then
echo " file=$CLAUDE_FILE_PATH" >> "$LOG_FILE"
fi
# 记录 Bash 命令(注意脱敏)
if [ "$TOOL" = "Bash" ]; then
COMMAND=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.command // empty')
# 脱敏:替换可能的密钥
SAFE_COMMAND=$(echo "$COMMAND" | sed -E 's/(key|token|password|secret)=[^ ]*/\1=***REDACTED***/gi')
echo " command=$SAFE_COMMAND" >> "$LOG_FILE"
fi
配置所有工具都记录日志:
{
"hooks": {
"PreToolUse": [
{
"matcher": ".*",
"hook": {
"type": "command",
"command": "bash .claude/hooks/audit-log.sh"
}
}
]
}
}
审计日志示例
[2026-03-11 14:23:01] session=abc123 tool=Read
file=src/components/Header.astro
[2026-03-11 14:23:05] session=abc123 tool=Edit
file=src/components/Header.astro
[2026-03-11 14:23:08] session=abc123 tool=Bash
command=npm run lint
[2026-03-11 14:23:15] session=abc123 tool=Bash
command=git add src/components/Header.astro
[2026-03-11 14:23:16] session=abc123 tool=Bash
command=git commit -m "feat(header): add search icon"
日志轮转
避免日志文件无限增长:
#!/bin/bash
# .claude/hooks/rotate-logs.sh
LOG_DIR=".claude/logs"
# 删除 30 天前的日志
find "$LOG_DIR" -name "audit-*.log" -mtime +30 -delete
团队安全策略
统一安全配置
在项目的 .claude/settings.json 中定义团队级安全策略:
{
"permissions": {
"allow": [
"Read",
"Glob",
"Grep",
"Write(src/**)",
"Write(tests/**)",
"Write(docs/**)",
"Edit(src/**)",
"Edit(tests/**)",
"Bash(npm run *)",
"Bash(npx *)",
"Bash(git *)"
],
"deny": [
"Write(.env*)",
"Write(*.pem)",
"Write(*.key)",
"Write(credentials*)",
"Bash(rm -rf *)",
"Bash(sudo *)",
"Bash(curl * | bash)",
"Bash(wget * | bash)",
"Bash(git push --force*)",
"Bash(git reset --hard*)",
"Bash(chmod 777 *)",
"Bash(npm publish*)"
]
},
"hooks": {
"PreToolUse": [
{
"matcher": ".*",
"hook": {
"type": "command",
"command": "bash .claude/hooks/audit-log.sh"
}
},
{
"matcher": "Bash",
"hook": {
"type": "command",
"command": "bash .claude/hooks/safety-check.sh"
}
}
]
}
}
安全配置的版本控制
.claude/
├── settings.json ← 团队共享,提交到 Git
├── settings.local.json ← 个人配置,不提交
└── hooks/
├── audit-log.sh ← 提交到 Git
├── safety-check.sh ← 提交到 Git
└── check-url.sh ← 提交到 Git
.gitignore 中:
.claude/settings.local.json
.claude/logs/
安全检查清单
在项目中使用 Claude Code 之前,过一遍这个清单:
文件安全
-
.gitignore包含所有敏感文件模式 -
.claudeignore排除了敏感目录 - 权限配置禁止写入敏感文件
- 环境变量通过
.env管理,不硬编码
命令安全
- 禁止了危险的 shell 命令
- 禁止了
sudo操作 - 禁止了
curl | bash模式 - 限制了
git push --force
网络安全
- 评估是否需要限制网络访问
- 如需限制,配置了域名白名单
- WebFetch 的使用有审计记录
审计
- 启用了操作审计日志
- 日志中敏感信息已脱敏
- 配置了日志轮转策略
团队
- 安全配置已提交到版本控制
- 团队成员了解安全策略
- 定期审查安全配置
常见安全场景
场景 1:防止 API Key 泄露
#!/bin/bash
# .claude/hooks/check-secrets.sh
# 在写入文件前检查是否包含密钥模式
INPUT="$CLAUDE_TOOL_INPUT"
CONTENT=$(echo "$INPUT" | jq -r '.content // .new_string // empty')
# 密钥模式
PATTERNS=(
'sk-[a-zA-Z0-9]{20,}'
'AKIA[0-9A-Z]{16}'
'ghp_[a-zA-Z0-9]{36}'
'glpat-[a-zA-Z0-9\-]{20,}'
'xoxb-[0-9]{10,}'
)
for pattern in "${PATTERNS[@]}"; do
if echo "$CONTENT" | grep -qE "$pattern"; then
echo "BLOCKED: 检测到可能的密钥/Token,请勿将敏感信息写入文件"
exit 1
fi
done
场景 2:限制文件系统访问范围
{
"permissions": {
"allow": [
"Read(src/**)",
"Read(tests/**)",
"Read(docs/**)",
"Read(package.json)",
"Read(tsconfig.json)",
"Read(*.config.*)"
],
"deny": [
"Read(/etc/**)",
"Read(/home/**/.ssh/**)",
"Read(~/.aws/**)",
"Read(~/.config/**)"
]
}
}
场景 3:生产环境保护
#!/bin/bash
# .claude/hooks/protect-production.sh
COMMAND=$(echo "$CLAUDE_TOOL_INPUT" | jq -r '.command // empty')
# 检查是否在操作生产环境
PROD_PATTERNS=(
"production"
"prod"
"--env=prod"
"deploy.*prod"
)
for pattern in "${PROD_PATTERNS[@]}"; do
if echo "$COMMAND" | grep -qi "$pattern"; then
echo "WARNING: 检测到可能影响生产环境的操作"
echo "命令: $COMMAND"
echo "如果确认需要执行,请手动在终端中运行"
exit 1
fi
done
安全与效率的平衡
安全配置不应该让 Claude Code 变得难以使用。这里有几个平衡的建议:
1. 分层配置
- 开发环境:宽松一些,提升效率
- CI 环境:严格一些,确保安全
- 生产相关:最严格,禁止大部分操作
2. 白名单优于黑名单
与其列举所有危险命令(总会遗漏),不如只允许已知安全的命令:
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test)",
"Bash(npm run build)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)"
]
}
}
3. 渐进式放开
刚开始使用时保持默认的 ask 模式,观察一段时间后,把确认安全的操作加入 allow 列表。
安全不是限制,而是信任的基础。当我们为 Claude Code 建立了清晰的安全边界,我们才能放心地让它发挥全部能力。好的安全实践不会减慢你的速度——它会让你跑得更快、更稳。
相关文章
评论
加载中...
评论
加载中...