Hooks 确定性安全栅栏:PreToolUse 拦截 + PostToolUse 自动格式化
本文是「Claude 企业级工程实战手册」专栏第 07 篇。CLAUDE.md 是建议性的(80% 遵守率),Hooks 是确定性的(100% 执行)。本文提供完整可用的拦截脚本和配置文件。
核心认知:建议性 vs 确定性
| 机制 | 类型 | 遵守率 | 适用场景 |
|---|---|---|---|
| CLAUDE.md 规则 | 建议性(Advisory) | ~80% | 代码风格、命名规范、架构偏好 |
| Hooks | 确定性(Deterministic) | 100% | 安全拦截、格式化、审计日志 |
凡是必须每次都发生的事,用 Hook。凡是"最好这样做"的规范,放 CLAUDE.md。
一、Hook 的触发机制
Claude 试图执行 Bash 工具(rm -rf /)
│
▼
PreToolUse Hook 触发
│
调用 pre_bash_sandbox_check.sh
│
┌───────┴───────┐
(高危命令) (安全命令)
▼ ▼
Exit Code 2 Exit Code 0
│ │
阻断执行 执行命令
返回原因
支持的 Hook 事件:
PreToolUse:工具调用前(Bash、Write、Edit 等)PostToolUse:工具调用后Stop:会话结束时SubagentStop:子 Agent 停止时
二、完整配置文件
.claude/settings.json
{
"$schema": "https://code.claude.com/docs/schema/settings.json",
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/pre_bash_sandbox_check.sh"
}
]
},
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/pre_write_protect.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/post_write_format.sh"
}
]
}
]
},
"compactPrompt": "在压缩会话历史时,必须完整保留 CLAUDE.md 中定义的禁忌规则、安全拦截规范,以及所有未解决的 TODO。严禁泛化合并。"
}
三、PreToolUse:高危命令拦截脚本
.claude/hooks/pre_bash_sandbox_check.sh
#!/bin/bash
# PreToolUse 拦截:阻断危险 Shell 命令与未授权操作
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
# 空命令直接放行
if [ -z "$COMMAND" ]; then
exit 0
fi
# ── 高危命令黑名单 ──
HIGH_RISK_PATTERNS=(
"rm -rf /"
"rm -rf ~"
"DROP TABLE"
"TRUNCATE TABLE"
"DELETE FROM .* WHERE 1=1"
"git push .* --force"
"chmod 777"
"> /etc"
"curl .* | bash"
"wget .* | sh"
)
for pattern in "${HIGH_RISK_PATTERNS[@]}"; do
if echo "$COMMAND" | grep -Ei -q "$pattern"; then
echo "🛑 SECURITY VIOLATION: 命令匹配高危禁忌正则 [$pattern]"
echo "该操作已被物理护栏强制截断。如确需执行,请手动运行并添加 # APPROVED 注释。"
exit 2
fi
done
# ── 生产环境写操作警告 ──
if echo "$COMMAND" | grep -Ei -q "\bprod\b|\bproduction\b"; then
echo "⚠️ WARN: 检测到命令涉及生产环境标示 [prod/production]"
echo "请确认你已获得完整授权,且已在沙箱中验证过该操作。"
# 仅警告,不阻断(如需阻断改为 exit 2)
fi
# ── 敏感文件写入检查 ──
SENSITIVE_FILES=(".env" ".env.production" "id_rsa" "*.pem" "secrets.yaml")
for pattern in "${SENSITIVE_FILES[@]}"; do
if echo "$COMMAND" | grep -q "$pattern"; then
echo "🔐 SECURITY: 检测到对敏感文件的写操作 [$pattern]"
echo "请确认这是你的本意,敏感文件不应由自动化脚本直接修改。"
exit 2
fi
done
exit 0
.claude/hooks/pre_write_protect.sh
#!/bin/bash
# PreToolUse 拦截:保护受限文件不被直接覆写
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# 受保护文件列表
PROTECTED_FILES=(
".env"
".env.production"
".env.staging"
"alembic.ini"
"pyproject.toml"
)
for protected in "${PROTECTED_FILES[@]}"; do
if [[ "$FILE_PATH" == *"$protected" ]]; then
echo "🔒 PROTECTED: 文件 [$FILE_PATH] 已被锁定,Claude 不能直接修改。"
echo "请手动编辑该文件,或在确认后移除保护。"
exit 2
fi
done
exit 0
四、PostToolUse:自动格式化脚本
.claude/hooks/post_write_format.sh
#!/bin/bash
# PostToolUse 自动格式化:保证落盘代码 100% 符合 Linter 标准
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# 空路径或文件不存在,跳过
if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then
exit 0
fi
# 按文件类型执行对应格式化
case "$FILE_PATH" in
*.py)
# Ruff:修正不规范导入、冗余变量,然后格式化
ruff check "$FILE_PATH" --fix --quiet 2>/dev/null
ruff format "$FILE_PATH" --quiet 2>/dev/null
echo "✅ Python 格式化完成:$FILE_PATH"
;;
*.ts|*.tsx|*.js|*.jsx)
npx prettier --write "$FILE_PATH" --loglevel silent 2>/dev/null
echo "✅ TypeScript/JavaScript 格式化完成:$FILE_PATH"
;;
*.json)
# 验证 JSON 格式
if ! python3 -c "import json; json.load(open('$FILE_PATH'))" 2>/dev/null; then
echo "⚠️ 警告:$FILE_PATH 不是合法的 JSON 文件"
fi
npx prettier --write "$FILE_PATH" --parser json --loglevel silent 2>/dev/null
;;
*.go)
gofmt -w "$FILE_PATH" 2>/dev/null
echo "✅ Go 格式化完成:$FILE_PATH"
;;
*.yaml|*.yml)
# YAML 格式验证
if ! python3 -c "import yaml; yaml.safe_load(open('$FILE_PATH'))" 2>/dev/null; then
echo "⚠️ 警告:$FILE_PATH 不是合法的 YAML 文件"
fi
;;
esac
exit 0
五、让脚本生效
# 1. 添加执行权限
chmod +x .claude/hooks/pre_bash_sandbox_check.sh
chmod +x .claude/hooks/pre_write_protect.sh
chmod +x .claude/hooks/post_write_format.sh
# 2. 确保依赖工具已安装
pip install ruff black # Python 格式化
npm install -g prettier # JS/TS 格式化
# 3. 验证 Hook 配置
cat .claude/settings.json | jq '.hooks'
# 4. 测试拦截效果(在 Claude Code 里运行)
# 输入:rm -rf /tmp/test
# 预期:被拦截,显示 SECURITY VIOLATION
六、企业进阶:集中式 Hook 管理
对于大型团队,Hook 脚本应集中管理:
# 通过 Git Submodule 引入团队共享 Hook 库
git submodule add https://github.com/your-org/claude-hooks .claude/shared-hooks
# 在 settings.json 中引用共享 Hook
# "command": "bash .claude/shared-hooks/security/pre_bash_check.sh"
下一篇:08. 三阶段工作流
专栏导航 · Claude 企业级工程实战手册
⬅️ 上一篇:06. CLAUDE.md 五层知识体系:让每个 Claude Code 会话自动对齐团队规范 ➡️ 下一篇:08. Claude Code 三阶段工作流:Plan Mode → 并行子 Agent → 物理验收标准
本专栏共 14 篇,系统覆盖 Claude 模型选型 / Prompt 工程 / Claude Code 工作流 / API 高级用法 / MCP / RAG / AI 安全合规全链路。欢迎收藏:Claude 企业级工程实战手册