Skill概述: 密钥扫描Skill是一种自动化安全检测工具,能够在代码提交前、CI/CD流水线中和代码仓库中实时扫描敏感信息泄露。本笔记全面讲解如何从零构建一个生产级别的密钥扫描Skill,涵盖模式识别、Git历史分析、误报处理、结果报告等核心能力。
一、密钥扫描Skill的设计
在现代软件开发中,敏感信息泄露是最常见且危害最严重的安全风险之一。开发者可能无意中将API Key、数据库凭证、私钥等敏感信息提交到代码仓库,一旦泄露到公开仓库或内部不安全的仓库,将导致严重的安全事故和经济损失。
1.1 核心设计目标
- 全面覆盖:支持数十种常见密钥格式的检测,覆盖主流云服务商、SaaS平台和数据库类型
- 历史追溯:不仅能扫描当前代码,还能检测Git历史提交中的密钥泄露
- 低误报率:通过上下文分析和模式排除机制,将误报率控制在5%以下
- 可扩展:插件化架构,用户可以自定义检测规则和排除模式
- 快速反馈:支持增量扫描和缓存机制,大型仓库扫描时间不超过30秒
1.2 Skill系统架构
扫描引擎
基于正则表达式和熵值检测的双引擎架构,支持精确匹配和启发式检测
规则库
内置100+条检测规则,覆盖API Key、Token、私钥、数据库连接串等
Git分析器
深度解析Git对象存储,扫描所有历史提交和引用日志
报告生成器
按严重程度分类输出结果,支持JSON/HTML/SARIF多种格式
1.3 工作流程
密钥扫描Skill的执行流程分为五个阶段:配置加载 -> 文件遍历 -> 模式匹配 -> Git历史分析 -> 结果聚合与报告。其中模式匹配阶段采用多线程并行处理,确保大型仓库的扫描效率。
关键设计原则: 密钥扫描Skill采用"纵深防御"理念,在多个关卡设置检测点——本地pre-commit钩子、CI/CD流水线扫描、定期全量仓库扫描,形成三道防线,最大程度降低泄露风险。
二、密钥模式识别
密钥模式识别是Skill的核心能力,通过正则表达式精确匹配已知格式的密钥,同时利用熵值分析(Entropy Analysis)检测高随机度字符串,捕获未知类型的凭证。
2.1 常见密钥格式检测规则
以下列举几类最常检测的密钥格式及其匹配模式:
| 密钥类型 |
格式特征 |
风险等级 |
| AWS Access Key ID |
AKIA[0-9A-Z]{16} |
严重 |
| AWS Secret Access Key |
wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY |
严重 |
| GitHub Personal Access Token |
ghp_[0-9a-zA-Z]{36} |
严重 |
| GitHub OAuth Access Token |
gho_[0-9a-zA-Z]{36} |
严重 |
| GitLab Personal Access Token |
glpat-[0-9a-zA-Z\-]{20,} |
严重 |
| SSH Private Key |
-----BEGIN (RSA|DSA|EC|OPENSSH) PRIVATE KEY----- |
严重 |
| Slack Bot Token |
xoxb-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24} |
高 |
| Stripe Live API Key |
sk_live_[0-9a-zA-Z]{24,} |
严重 |
| Google OAuth Client Secret |
[0-9a-zA-Z\-_]{24} |
高 |
2.2 数据库连接串检测
数据库连接串通常包含明文密码,是泄露后的高危目标。Skill支持检测以下格式的连接串:
# MySQL 连接串
mysql://username:password123@localhost:3306/mydatabase
# PostgreSQL 连接串
postgresql://user:secretpass@pg-host:5432/dbname?sslmode=require
# MongoDB 连接串
mongodb+srv://admin:passw0rd@cluster0.abcde.mongodb.net/myDB
# Redis 连接串
redis://:authpassword@redis-host:6379/0
# JDBC 连接串
jdbc:mysql://localhost:3306/mydb?user=root&password=secret123
2.3 JWT Token 检测
JWT Token通常由三个Base64编码的部分组成,格式为 `xxxxx.yyyyy.zzzzz`。Skill通过正则和Base64解码验证双重机制检测JWT Token,同时检查Token中是否包含敏感声明(如 `admin`、`root` 等高权限标识)。
# JWT Token 格式示例
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
2.4 熵值检测(Entropy Analysis)
除了正则匹配,Skill还实现了基于信息熵的启发式检测。对于高随机度的字符串(如 `X7mK9pQ2vR5nL8jF3tW1cY4`),即使不在已知格式库中,也会被标记为可疑。熵值算法的阈值为:
- 高熵字符串(熵值 > 4.5):长度超过20字符的高随机度字符串,标记为潜在密钥
- 中熵字符串(熵值 3.5 - 4.5):长度超过30字符,进一步上下文分析
- 低熵字符串(熵值 < 3.5):通常为普通变量名或注释,自动排除
最佳实践: 建议将正则检测和熵值检测结合使用。正则检测提供精确匹配(低误报),熵值检测提供广度覆盖(低漏报)。在生产环境中,正则可以设为error级别,熵值检测设为warning级别。
三、Git历史扫描
仅扫描当前工作目录是不够的——敏感信息可能存在于历史提交中,即使后续删除,仍然可以从Git历史中恢复。Git历史扫描是密钥扫描Skill最具价值的能力之一。
3.1 扫描所有Commit历史
Skill使用 `git log -p` 或底层 `git cat-file` 命令遍历仓库中的所有提交对象,对每个提交的diff内容进行密钥检测。这意味着即使密钥在后续提交中被删除,也能被检出。
# 扫描所有历史提交中的敏感信息
$ git log --all --full-history --diff-filter=AM --pickaxe-all -p | scan-secrets
# 也可以逐个commit扫描(更精确)
$ for commit in $(git rev-list --all); do
git diff-tree --no-commit-id -r $commit | scan-secrets
done
3.2 检测已删除文件的密钥痕迹
即使文件已被删除,只要它曾经存在于仓库中,其内容仍然可以通过Git对象存储访问。Skill会扫描所有Git对象(包括那些不属于任何分支引用的孤儿对象),确保不会遗漏。
安全警示: Git并不会真正删除数据。即使执行了 `git rm` 和新的提交,旧数据仍然存在于 `.git/objects/` 目录中,直到执行垃圾回收(`git gc`)并且没有任何引用指向这些对象。在公开仓库中,任何曾经提交过的密钥都应视为"已泄露"并立即轮换。
3.3 查找reflog中的密钥记录
Git的reflog记录了所有HEAD引用的变更历史,包括被重置或变基丢弃的提交。密钥扫描Skill会检查 `git reflog show --all` 的输出,确保这些"已消失"的提交中的密钥也被检出。
# 扫描reflog中的敏感信息
$ git reflog show --all --format="%H" | while read hash; do
git show $hash 2>/dev/null | scan-secrets
done
3.4 识别从公开仓库复制的密钥
Skill还会检查代码中是否存在已知的公开泄露密钥(基于公开的泄露密钥数据库)。如果在代码库中发现与已知泄露密钥匹配的字符串,将标记为"已公开泄露",严重级别自动升级为最高。
实战建议: 对于新初始化的仓库,建议在第一次提交前运行一次全量Git历史扫描。对于已有大量历史提交的仓库,可以使用 `git filter-branch` 或 `BFG Repo-Cleaner` 清除历史中的敏感信息后,再执行强制推送覆盖。
四、误报排除和分类
密钥扫描的难点不在于"找出所有可能的密钥",而在于"找出的东西确实是密钥"。一个好的Skill必须有完善的误报排除机制和清晰的风险分类体系。
4.1 风险等级分类
| 级别 |
标识 |
说明 |
处理动作 |
| 严重 (Critical) |
🔴 |
活密钥,连接后可访问生产环境资源 |
立即轮换,检查访问日志 |
| 高 (High) |
🟠 |
疑似活密钥,格式完全匹配但无法验证 |
人工确认,72小时内处理 |
| 中 (Medium) |
🟡 |
格式匹配但在测试或示例文件中 |
确认上下文,排除或清理 |
| 低 (Low) |
🟢 |
熵值检测的可疑字符串,格式不明确 |
人工审查,更新排除规则 |
4.2 内置误报排除规则
为了减少人工审查负担,Skill内置了多层误报排除机制:
- 路径排除:自动跳过 `test/`、`tests/`、`__tests__/`、`example/`、`samples/`、`vendor/`、`node_modules/` 等目录
- 文件扩展名排除:跳过 `.md`(文档中的示例)、`.txt`(纯文本示例)、`.rst`、`.log` 中的已知假阳性模式
- 正则白名单:允许配置特定的正则模式作为白名单,例如 `your-actual-key-here`、`CHANGE_ME`、`YOUR_KEY_HERE` 等占位符模式
- 上下文分析:检查密钥所在行的上下文变量名,如果包含 `example`、`sample`、`placeholder`、`dummy`、`fake` 等关键词,自动降级或排除
# 排除规则配置示例 (YAML格式)
exclude:
paths:
- "**/tests/**"
- "**/examples/**"
- "**/fixtures/**"
patterns:
- "your-actual-key-here"
- "CHANGE_ME"
- "\\$\\{[A-Z_]+\\}" # 环境变量占位符
context_keywords:
- "example"
- "placeholder"
- "dummy"
- "fake"
- "sample"
4.3 人工确认结果列表
经过自动分类和排除后,Skill输出一个结构化的人工确认清单。每个结果包含完整上下文(前后5行代码)、文件路径、行号、匹配类型和严重级别。支持将结果导出为JSON格式,方便集成到Jira、PagerDuty等工作流系统中。
// 扫描结果JSON输出示例
{
"findings": [
{
"type": "aws_secret_key",
"severity": "critical",
"file": "src/config/production.js",
"line": 42,
"commit": "a1b2c3d4e5f6...",
"committer": "developer@company.com",
"date": "2026-05-01T10:30:00Z",
"context": "accessKeyId: 'AKIA...'"
}
],
"summary": {
"total_scanned": 15234,
"critical": 1,
"high": 3,
"medium": 7,
"low": 12,
"false_positives_excluded": 45
}
}
4.4 密钥轮换建议
当检测到已泄露的密钥时,Skill会针对不同类型的密钥给出具体的轮换建议:
- AWS Key:通过AWS IAM控制台或CLI执行 `aws iam create-access-key` 创建新密钥,然后更新所有使用该密钥的应用程序配置,最后 `aws iam delete-access-key` 删除旧密钥
- GitHub Token:在GitHub Settings > Developer settings > Personal access tokens 中生成新Token,更新CI/CD配置和自动化脚本
- 数据库密码:执行 `ALTER USER` 更改数据库密码,更新所有连接串配置。对于连接池中的长连接,可能需要重启服务
- SSH Key:生成新的SSH密钥对(`ssh-keygen -t ed25519`),将公钥添加到服务器授权列表,更新Git远程URL
重要提醒: 密钥轮换时不应急于删除旧密钥。应该采用"先创建新密钥 -> 逐步迁移 -> 确认旧密钥不再使用 -> 最后删除"的四步策略。对于生产环境中的API Key,建议设置24小时的重叠期,确保所有服务都已更新。
技能要点总结: 一个优秀的密钥扫描Skill = 精确的规则匹配 + 深度Git历史扫描 + 智能误报排除 + 清晰的分级报告。在DevSecOps实践中,将密钥扫描集成到CI/CD流水线的早期阶段,可以在密钥造成实际危害之前及时发现和处理。