首页 › tutorials › 造密钥扫描Skill实战开发

概述

本教程带你从零开发一个名为 secret-scanner 的自定义 Claude Code Skill,它能在代码库里自动发现硬编码的密钥、API Key、令牌和私钥,并产出一份按严重度排序的修复报告。学完你将掌握 SKILL.md 的结构、YAML frontmatter 各字段、渐进披露(progressive disclosure)设计、捆绑脚本与模板的组织方式,以及如何让技能精准触发、安全受限地运行。适合已经用过 Claude Code、想把重复性工作固化成可复用能力的中级开发者。

前置条件


一、先想清楚:一个 Skill 到底是什么

Claude Code 的 Skill 本质上是一个文件夹,核心文件是 SKILL.md。文件夹里还可以放脚本、模板、参考文档等任意资产。Claude 不会一次性把整个技能加载进上下文,而是采用渐进披露(progressive disclosure)机制:

这套机制决定了写 Skill 的两条铁律:

  1. description 要写成"何时该用"——它是技能唯一的触发入口,写得越具体、越带场景词,触发越精准。
  2. 正文要短,细节下沉到子文件——把长规则、大段示例挪到 rules/、templates/、scripts/,让 Claude 按需加载,避免污染上下文。

与斜杠命令(slash command)的区别:斜斜命令需要用户手动输入 /xxx 才触发;而带 description 的 Skill 可以被模型自动唤起,也能用 /技能名 显式调用。本教程做的是会自动触发的 Skill。


二、规划目录结构

先在脑中画出最终形态,再动手写文件,能少走弯路。我们的 secret-scanner 结构如下:

~/.claude/skills/secret-scanner/
├── SKILL.md              # 入口:frontmatter + 精简工作流
├── scripts/
│   └── scan.py           # 扫描引擎,输出 JSON 结果
├── templates/
│   └── report.md         # 报告模板
└── rules/
    ├── patterns.md       # 完整正则规则与误报处理(按需加载)
    └── remediation.md    # 各类密钥的轮换/撤销指引(按需加载)

Skill 可以放在三个位置,按就近原则生效:

位置 路径 适用场景
个人级 ~/.claude/skills/<name>/ 所有项目通用的工具型技能
项目级 <repo>/.claude/skills/<name>/ 随仓库走、团队共享,与代码强相关
插件级 随 Plugin 分发 发布到团队市场,跨项目复用

我们把 secret-scanner 放个人级,因为它在任何项目里都用得上。


三、第一步:创建目录与 SKILL.md 的 frontmatter

创建目录并新建入口文件:

mkdir -p ~/.claude/skills/secret-scanner/{scripts,templates,rules}

写入 ~/.claude/skills/secret-scanner/SKILL.md 的 frontmatter 部分:

---
name: secret-scanner
description: Scans the codebase for hardcoded secrets, API keys, tokens and private keys, then writes a prioritized remediation report. Use when the user asks to check for leaked credentials, audit secrets/API keys, harden code before commit/push, or run a pre-commit security scan.
---

字段详解:

flowchart TD
    A[用户输入: '帮我查下有没有泄露的密钥'] --> B{匹配 description?}
    B -- 命中触发词 --> C[加载 SKILL.md 正文]
    B -- 未命中 --> D[不触发该技能]
    C --> E{正文引用脚本/规则?}
    E -- 是 --> F[按需读取 scripts/scan.py]
    E -- 否 --> G[直接按正文指令行动]
    F --> H[运行扫描并产出报告]

常见问题:技能死活不自动触发?九成是 description 没写好。把"Use when"那句的触发词换成你实际会说的中文/英文表达,再试。


四、第二步:写精简的正文(渐进披露的核心)

frontmatter 下面就是正文。正文不要超过约 500 字,把"怎么做"压缩成清晰的工作流,细节丢给子文件:

# 密钥泄露扫描

当用户请求扫描密钥 / 检查泄露凭证 / 审计安全时激活本技能。

## 工作流程
1. 运行扫描引擎:`python3 scripts/scan.py <目标目录>`(默认扫描当前目录)
2. 读取返回的 JSON 结果
3. 按严重度排序:私钥 > AWS/GitHub/Stripe 等高敏凭据 > 通用密钥
4. 用 `templates/report.md` 作为骨架,生成报告
5. 每条发现给出修复建议(迁移到环境变量 / 密钥管理服务 / 立即撤销轮换)

## 细节按需加载
- 完整正则规则与**误报处理策略**见 `rules/patterns.md`
- 各类密钥的**轮换与撤销指引**见 `rules/remediation.md`

## 输出与安全要求
- 报告写入项目根目录 `SECRET-SCAN-REPORT.md`
- **绝不**在报告里打印完整密钥明文,只显示前 6 位 + `***`
- 发现私钥或生产令牌时,在报告顶部用"🔴 紧急"标注并提醒立即撤销

注意最后一句"细节按需加载"——这正是渐进披露的落地:Claude 默认不读 rules/,只有当它需要判断"这条匹配是不是误报"时,才会去打开 rules/patterns.md。


五、第三步:写扫描引擎 scripts/scan.py

技能的价值很大程度上来自捆绑的脚本。在 scripts/scan.py 写入一个可独立运行的正则扫描器:

#!/usr/bin/env python3
"""secret-scanner: 在代码库中扫描硬编码密钥,输出 JSON。"""
import re, sys, os, json

# (规则名, 正则, 严重度)
RULES = [
    ("Private Key Block",  r"-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----", "critical"),
    ("AWS Access Key",     r"AKIA[0-9A-Z]{16}", "high"),
    ("AWS Secret Key",     r"aws_secret_access_key\s*=\s*['\"][A-Za-z0-9/+=]{40}['\"]", "high"),
    ("GitHub Token",       r"gh[pousr]_[A-Za-z0-9]{36,}", "high"),
    ("Google API Key",     r"AIza[0-9A-Za-z_\-]{35}", "high"),
    ("Stripe Secret Key",  r"sk_live_[A-Za-z0-9]{24,}", "high"),
    ("Slack Token",        r"xox[baprs]-[A-Za-z0-9-]{10,}", "medium"),
    ("Generic Secret",     r"(?i)(password|passwd|pwd|secret|token|api[_-]?key)\s*[:=]\s*['\"][^'\"]{16,}['\"]", "medium"),
]

SKIP_DIRS = {"node_modules", ".git", "venv", ".venv", "__pycache__", "dist", "build"}
SCAN_EXT  = {".py", ".js", ".ts", ".go", ".java", ".rb", ".php",
             ".env", ".yml", ".yaml", ".json", ".sh", ".conf", ".ini", ".toml", ".tf"}

def scan(root):
    findings = []
    for dirpath, dirnames, files in os.walk(root):
        dirnames[:] = [d for d in dirnames if d not in SKIP_DIRS]   # 原地剪枝
        for f in files:
            if os.path.splitext(f)[1] not in SCAN_EXT:
                continue
            fp = os.path.join(dirpath, f)
            try:
                with open(fp, encoding="utf-8", errors="ignore") as fh:
                    for i, line in enumerate(fh, 1):
                        for name, pat, sev in RULES:
                            if re.search(pat, line):
                                findings.append({
                                    "file": fp, "line": i, "rule": name,
                                    "severity": sev,
                                    "snippet": line.strip()[:80],
                                })
            except OSError:
                pass
    findings.sort(key=lambda x: ["critical","high","medium"].index(x["severity"]))
    return findings

if __name__ == "__main__":
    target = sys.argv[1] if len(sys.argv) > 1 else "."
    print(json.dumps(scan(target), indent=2, ensure_ascii=False))

赋予执行权限,确保 Claude 能直接调用:

chmod +x ~/.claude/skills/secret-scanner/scripts/scan.py

这段脚本的设计要点:


六、第四步:写规则文档与报告模板(按需加载层)

rules/patterns.md 示例(只放 Claude 需要判断误报时才读的细节):

# 密钥匹配规则与误报处理

## 已知误报
- 示例代码、文档、单测 fixture 里的假密钥(如 `AKIAIOSFODNN7EXAMPLE`)应忽略
- 环境变量**引用**(`os.getenv("AWS_KEY")`)不是泄露,只有**赋值字面量**才算

## 处理策略
- 若文件名含 `test/`、`example/`、`docs/` 或后缀 `.md`,降低严重度一档
- 对 Generic Secret 规则,先确认右侧是否为占位符(`your-key-here`、`xxx`),是则跳过

templates/report.md 报告骨架:

# 🔐 密钥泄露扫描报告

扫描时间:{{date}} 扫描目录:{{target}}
**发现 {{count}} 处疑似泄露**(🔴 紧急 {{critical}} / 🟠 高危 {{high}} / 🟡 中危 {{medium}})

## 紧急处理清单
> 含私钥或生产令牌的项目,请立即在各服务商后台**撤销并轮换**对应凭证。

| 严重度 | 文件 | 行号 | 规则 | 片段(已脱敏) |
|--------|------|------|------|----------------|
{{rows}}

## 修复建议
- [ ] 将所有硬编码密钥迁移到环境变量或密钥管理服务(AWS Secrets Manager / Vault)
- [ ] 撤销已泄露的凭证并轮换
- [ ] 在 `.gitignore` 中加入 `.env`,并考虑接入 pre-commit 的密钥扫描钩子

七、第五步:造一个测试场,验证整条链路

新建测试目录,故意埋几个假密钥:

mkdir -p /tmp/demo-app && cd /tmp/demo-app
cat > config.py <<'EOF'
AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE"
GITHUB_TOKEN   = "ghp_0123456789abcdef0123456789abcdef0123"
api_key = os.getenv("STRIPE_KEY")   # 这是引用,不应报
EOF
cat > id_rsa.bak <<'EOF'
-----BEGIN RSA PRIVATE KEY-----
fakecontent
-----END RSA PRIVATE KEY-----
EOF

先独立验证脚本:

python3 ~/.claude/skills/secret-scanner/scripts/scan.py /tmp/demo-app

预期输出(JSON):

[
  {
    "file": "/tmp/demo-app/id_rsa.bak",
    "line": 1,
    "rule": "Private Key Block",
    "severity": "critical",
    "snippet": "-----BEGIN RSA PRIVATE KEY-----"
  },
  {
    "file": "/tmp/demo-app/config.py",
    "line": 2,
    "rule": "GitHub Token",
    "severity": "high",
    "snippet": "GITHUB_TOKEN   = \"ghp_0123456789abcdef0123456789abcdef0123\""
  }
]

注意 api_key = os.getenv(...) 这行不会出现在结果里——这正是 rules/patterns.md 里"环境变量引用不算泄露"的预期行为(脚本层面靠正则只匹配字面量赋值实现)。


八、第六步:让 Claude Code 触发并使用这个技能

回到任意项目,启动 Claude Code,输入一句自然语言:

帮我扫一下当前项目里有没有泄露的密钥

预期发生的事:模型识别到"扫描密钥/泄露"等触发词,自动加载 secret-scanner 的正文,然后执行 scan.py,最后按 templates/report.md 写出 SECRET-SCAN-REPORT.md。

你也可以显式调用:直接输入技能名 secret-scanner,或用它对应的斜杠形式。若想强制只能手动触发、不允许自动唤起,在 frontmatter 加一行:

disable-model-invocation: true

九、第七步:收紧权限——给技能上"最小权限"

默认情况下技能继承会话的全部工具。出于安全考虑,应限制 secret-scanner 只能读文件、只能跑它自己的脚本。在 frontmatter 增加:

allowed-tools: Bash(python3 scripts/scan.py:*), Read, Write(SECRET-SCAN-REPORT.md)

这样该技能不能执行 rm、git push、联网等危险操作,即便被恶意输入诱导也无法越权。

sequenceDiagram
    participant U as 用户
    participant C as Claude Code
    participant S as secret-scanner 技能
    participant P as scan.py
    U->>C: "扫描项目里的密钥"
    C->>S: description 命中,加载 SKILL.md
    S->>P: 运行 python3 scripts/scan.py .
    P-->>S: 返回 JSON 发现清单
    S->>S: 按模板脱敏 + 排序
    S-->>C: 写入 SECRET-SCAN-REPORT.md
    C-->>U: 报告摘要 + 修复建议

十、完整实战案例回顾

把以上片段拼起来,一个完整可运行的技能就成型了。最终交付:

  1. 一个能自动触发的 secret-scanner Skill;
  2. 一份按严重度排序、自动脱敏的扫描报告;
  3. 受限的工具权限,安全可控;
  4. 可演进:往 RULES 里加正则、往 rules/ 里加误报策略即可持续增强,无需改动入口。

进阶玩法:


训练营适用性评估

维度 评估
适合训练营 ✅ 中级开发者训练营、安全工程训练营、AI 工程化训练营
教学时长 约 90–120 分钟(含动手造测试场与联调)
学员产出 每人一个可运行的 secret-scanner 技能 + 扫描报告
前置衔接 建议先上"读懂智能体循环"或"四层配置装通 Claude Code"
后续延伸 可衔接 Plugin 打包、Hook 自动化、MCP 服务器开发等进阶主题

参考来源

  1. Extend Claude with skills — Claude Code Docs — Anthropic 官方 Skills 文档,权威说明 SKILL.md 结构、frontmatter 与渐进披露机制。
  2. Claude Code Skill Frontmatter: Every YAML Option Explained — 逐字段讲解 name、description、allowed-tools、disable-model-invocation 等 15 个 frontmatter 字段。
  3. How to Build Claude Code Skills: 5 Examples (2026) — 含 5 个完整示例,覆盖 SKILL.md 规范、安全控制与团队分发工作流。
  4. Creating custom skills — Claude.ai Documentation — 官方关于向技能目录添加 resources、scripts、reference 文档的指引。
  5. Build a Claude Skill: YAML Frontmatter, SKILL.md Instructions — 动手实战教程,讲解 SKILL.md 格式与正文撰写。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入