Agent工坊

【Agent工坊】Claude Code Hooks实战:3个钩子让你的AI编程助手安全10倍

【Agent工坊】Claude Code Hooks实战:3个钩子让你的AI编程助手安全10倍

你用Claude Code写了1000行代码,但其中37行存在安全漏洞——因为没有人审查AI的每一次工具调用。Hooks系统就是你的自动化代码审查官。


为什么你需要Hooks

Claude Code是目前最强的AI编程助手之一,但它有一个致命弱点:它不会自我审查。


当你让Claude Code"帮我修复这个SQL注入漏洞",它会直接修改代码。但你怎么知道它不会在修复的过程中引入新的安全问题?怎么确保它不会误删关键的业务逻辑?


答案藏在Claude Code的 Hooks系统 里。


Hooks是一种事件驱动的拦截机制,允许你在AI Agent执行工具调用的前后插入自定义逻辑。用人话翻译:你可以在Claude Code每次动手之前和之后,自动运行你自己的检查脚本。


这是AI创业者必须掌握的能力——因为当你的Agent在凌晨3点自动修改生产代码时,你需要一个不睡觉的安全网。


Hooks机制速览

Claude Code支持 9种Hook事件,今天聚焦最核心的3种:


Hook类型触发时机典型用途
PreToolUse工具调用之前拦截危险命令、注入安全规则
PostToolUse工具调用之后自动格式化、记录日志、二次校验
StopAgent决定停止时最终完整性检查、生成审计报告

配置文件路径:~/.claude/settings.json 或项目级 .claude/settings.local.json


实战一:PreToolUse — 拦截危险命令

AI Agent最让人担心的是什么?它可能会执行 rm -rf /、DROP TABLE 或 git push --force。PreToolUse Hook就是你的最后一道防线。


场景:你想让Claude Code自由编辑代码,但禁止它操作git、修改数据库、或执行任何涉及 rm 的命令。


在 .claude/settings.local.json 中添加:


{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/bash-guard.py"
          }
        ]
      }
    ]
  }
}


配套Python脚本 ~/.claude/hooks/bash-guard.py:


#!/usr/bin/env python3
"""PreToolUse hook: 拦截Bash危险命令"""
import json, sys, os

# Claude Code 通过 stdin 传入工具调用信息
tool_input = json.loads(sys.stdin.read())
command = tool_input.get("command", "")
tool_name = tool_input.get("tool_name", "")

# 黑名单规则
DANGEROUS_PATTERNS = [
    "rm -rf", "rm -r", "git push --force",
    "DROP TABLE", "DROP DATABASE",
    "chmod 777", "> /dev/sda",
    "format C:", "dd if=",
    ":(){ :|:& };:",  # fork bomb
]

for pattern in DANGEROUS_PATTERNS:
    if pattern.lower() in command.lower():
        # 返回 blocked 决策 + 解释
        result = {
            "decision": "block",
            "reason": f"⚠️ 检测到危险命令模式: '{pattern}'。"
                      f"如有必要,请手动确认后执行。"
        }
        print(json.dumps(result))
        sys.exit(0)

# 放行
print(json.dumps({"decision": "allow"}))


效果:当Claude Code想执行 git push --force origin main 时,Hook会直接拦截并返回原因,Agent会收到反馈并调整策略。


实战二:PostToolUse — 自动格式化 + 日志审计

PreToolUse负责"拦截",PostToolUse负责"善后"。AI改完代码后,你需要确保格式规范、没有引入明显bug。


场景:每次Claude Code修改Python文件后,自动运行 black 格式化,再运行 ruff check 静态分析,最后记录所有变更到审计日志。


{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/post-edit.py"
          }
        ]
      }
    ]
  }
}


~/.claude/hooks/post-edit.py:


#!/usr/bin/env python3
"""PostToolUse hook: 格式化 + 静态检查 + 审计日志"""
import json, sys, subprocess, time
from pathlib import Path

tool_input = json.loads(sys.stdin.read())
file_path = tool_input.get("file_path", "")

if not file_path or not file_path.endswith(".py"):
    print(json.dumps({"decision": "allow"}))
    sys.exit(0)

results = []

# 1. 自动格式化
if Path(file_path).exists():
    r = subprocess.run(
        ["black", "--quiet", file_path],
        capture_output=True, text=True, timeout=15
    )
    results.append(f"Black: {'OK' if r.returncode==0 else r.stderr[:100]}")

# 2. 静态分析
    r = subprocess.run(
        ["ruff", "check", "--select=E,F", file_path],
        capture_output=True, text=True, timeout=15
    )
    if r.returncode != 0:
        results.append(f"⚠️ Ruff: {r.stdout.strip()[:200]}")
    else:
        results.append("Ruff: PASS")

# 3. 审计日志
audit_log = Path.home() / ".claude" / "audit.log"
with open(audit_log, "a") as f:
    f.write(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] "
            f"Edited: {file_path} | {results}\n")

print(json.dumps({
    "decision": "allow",
    "systemMessage": f"🔧 Post-edit 检查完成: {'; '.join(results)}"
}))


效果:每次AI编辑代码,你的项目自动保持PEP 8格式,任何语法错误会被立即捕获,所有操作留有审计轨迹——就像给AI配了一个不睡觉的代码审查官。


实战三:Stop Hook — 最终完整性检查

Stop Hook是Agent决定"我完成了"时触发的最后一道关卡。此时你可以运行测试套件、检查TODO残留、验证关键文件未丢失。


{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.claude/hooks/stop-check.py"
          }
        ]
      }
    ]
  }
}


~/.claude/hooks/stop-check.py:


#!/usr/bin/env python3
"""Stop hook: 最终完整性检查"""
import json, sys, subprocess
from pathlib import Path

issues = []

# 检查1: 是否有未提交的TODO
for py_file in Path(".").rglob("*.py"):
    content = py_file.read_text()
    if "TODO" in content or "FIXME" in content:
        lines = [f"  L{idx+1}: {line.strip()}" for idx, line
                 in enumerate(content.split("\n"))
                 if "TODO" in line or "FIXME" in line]
        issues.append(f"📝 {py_file} 残留TODO/FIXME:\n" + "\n".join(lines[:3]))

# 检查2: 测试是否通过
r = subprocess.run(
    ["pytest", "-x", "--tb=short"],
    capture_output=True, text=True, timeout=60
)
if r.returncode != 0:
    issues.append(f"❌ 测试失败:\n{r.stdout[-500:]}")

# 检查3: Git状态
r = subprocess.run(
    ["git", "status", "--porcelain"],
    capture_output=True, text=True
)
changed = len(r.stdout.strip().split("\n")) if r.stdout.strip() else 0
if changed > 0:
    issues.append(f"📂 未提交变更: {changed}个文件")

if issues:
    msg = "## ⚠️ Stop Hook 发现问题 ##\n" + "\n\n".join(issues)
    print(json.dumps({"decision": "block", "reason": msg}))
else:
    print(json.dumps({"decision": "allow",
                      "systemMessage": "✅ 全部检查通过,可以放心提交!"}))


效果:Agent告诉你"任务完成"时,Stop Hook会跑一遍完整检查——残留TODO?测试挂了?有文件没提交?任何一项不合格,Agent就不能"下班"。


组合使用:三合一安全网

把三个Hook串联起来,你得到了一条完整的安全流水线:


用户请求 "修复登录页的SQL注入"
        │
        ▼
PreToolUse Hook ── 拦截 rm -rf / DROP TABLE 等危险操作
        │
        ▼
Claude Code 执行文件编辑
        │
        ▼
PostToolUse Hook ── Black格式化 → Ruff检查 → 审计日志
        │
        ▼
Agent 认为完成
        │
        ▼
Stop Hook ── TODO残留检查 → pytest → git status
        │
        ▼
    ✅ 全部通过 → 任务完成
    ❌ 发现问题 → Agent继续修复


避坑指南

经过实测,这里有几个新手最容易踩的坑:


坑1:Hook返回格式错误导致静默失败。 Hook的stdout必须是合法的JSON,且包含 decision 字段("allow"或"block")。如果JSON格式错误,Claude Code会静默跳过Hook——你的安全检查就白写了。


坑2:Python环境问题。 Hook脚本里的 python3 需要指向你安装了依赖(black、ruff、pytest)的Python环境。建议在脚本开头显式指定完整路径或使用虚拟环境。


坑3:超时设置。 Hook执行时间过长会被Claude Code强制终止。PostToolUse 建议10秒内完成,Stop 可以放宽到60秒。在脚本中尽量避免网络请求。


坑4:Hook路径必须用绝对路径。 ~/.claude/hooks/xxx.py 中的 ~ 不会被自动展开,必须写成 /home/username/.claude/hooks/xxx.py 或用 $HOME。


坑5:循环陷阱。 如果你的PostToolUse Hook自己也调用了文件编辑工具,可能会触发新的PostToolUse,形成无限循环。解决方案:在Hook中检查环境变量 SKIP_HOOKS=1 来跳过递归。


# 在Hook脚本开头添加递归保护
import os
if os.environ.get("SKIP_HOOKS") == "1":
    print(json.dumps({"decision": "allow"}))
    sys.exit(0)


总结

这三组Hook加起来不到150行代码,但它们在每次AI Agent操作时都会自动运行审查——这就是自动化质量控制的核心。


对于AI创业者来说,Hooks系统有三层价值:


  1. 安全兜底:AI可能出错,但你的Hook不会漏检
  2. 规范统一:无论谁用Claude Code,产出的代码都经过同一套检查
  3. 可审计:每条变更都有日志,出问题能追溯

行动建议:现在就打开你的 .claude/settings.local.json,先把PreToolUse的 rm -rf 拦截加上。这是10行配置就能避免的灾难。



#AI创业 #Agent工坊 #ClaudeCode #Hooks #一人公司

本文由AI辅助创作,经人工审核编辑发布