本文目录导读:

Git 钩子脚本可以用来在提交、推送等操作前自动检查代码中是否存在潜在的敏感信息(如密码、密钥、Token、内网IP等),以下是一个实用的、用于检查脱敏策略的 pre-commit 钩子 脚本实现方案。
基本思路
- 使用
grep或正则表达式匹配常见的敏感信息模式 - 扫描暂存区(staged)的文件,而非全部工作区
- 发现敏感信息时阻止提交,并给出提示
通用 pre-commit 钩子脚本示例
将这个脚本保存为 .git/hooks/pre-commit,并赋予执行权限(chmod +x .git/hooks/pre-commit)。
#!/bin/sh
# pre-commit 钩子 - 检查敏感信息
# 定义颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo "${YELLOW}检查敏感信息中...${NC}"
# 检测敏感信息的关键词/正则表达式列表
SENSITIVE_PATTERNS=(
# 密码相关
"(password|passwd|pwd)\s*[=:]\s*['\"]?[^'\"\s]{4,}"
# API密钥/Token
"(api[_-]?key|api[_-]?secret|access[_-]?key|secret[_-]?key|private[_-]?key|token)\s*[=:]\s*['\"]?[^'\"\s]{8,}"
# AWS密钥 (AKIA开头)
"AKIA[0-9A-Z]{16}"
# 私钥标记
"-----BEGIN (RSA|DSA|EC|OPENSSH|PGP) PRIVATE KEY-----"
# 连接字符串中的密码
"://[^:/\s]+:[^@\s]+@"
# 常见的秘密/密钥
"secret\s*[=:]\s*['\"]?[^'\"\s]{8,}"
# Google Service Account
"type\s*:\s*service_account"
# 内网IP (可选的,根据策略)
"10\.\d{1,3}\.\d{1,3}\.\d{1,3}"
"172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}"
"192\.168\.\d{1,3}\.\d{1,3}"
)
# 获取暂存区中要提交的文件列表(排除二进制文件)
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -v '.png$\|.jpg$\|.jpeg$\|.gif$\|.ico$\|.pdf$\|.exe$\|.dll$\|.so$\|.class$')
# 获取变更行(只检查新增/修改的行)
CHANGES=$(git diff --cached -U0 -- ${STAGED_FILES})
# 用于标记是否发现敏感信息
HAS_SENSITIVE=false
# 遍历每个敏感模式
for pattern in "${SENSITIVE_PATTERNS[@]}"; do
# 使用 grep 检查 (排除注释行)
MATCHES=$(echo "$CHANGES" | grep -n -E "$pattern" | grep -v "^[+-]?\s*#" | grep -v "^[+-]?\s*//" | grep -v "^[+-]?\s*/\*")
if [ -n "$MATCHES" ]; then
echo "${RED}⚠️ 发现可能敏感信息: ${pattern}${NC}"
echo "$MATCHES" | head -5
HAS_SENSITIVE=true
fi
done
# 自定义白名单文件(允许包含敏感信息的文件)
WHITELIST=(
".env.example"
"config/sample.yaml"
)
if [ "$HAS_SENSITIVE" = true ]; then
echo ""
echo "${RED}═══════════════════════════════════════════════${NC}"
echo "${RED}❌ 提交被阻止: 检测到可能的敏感信息${NC}"
echo "${RED}请移除上述敏感数据后再提交,或使用:${NC}"
echo "${YELLOW} git commit --no-verify (跳过钩子检查,不推荐)${NC}"
echo "${RED}═══════════════════════════════════════════════${NC}"
exit 1
fi
echo "${GREEN}✅ 敏感信息检查通过${NC}"
exit 0
更全面的检测模式增强
如果策略需要更严格的检查,可以扩展检测模式:
# 更全面的模式
SENSITIVE_PATTERNS+=(
# JWT Token
"eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+"
# 各种Token/哈希
"(ghp|gho|ghu|ghs|ghr)_[a-zA-Z0-9]{36}" # GitHub Token
"xox[baprs]-[a-zA-Z0-9-]{24,}" # Slack Token
"sk_live_[0-9a-zA-Z]{24,}" # Stripe Live Key
"pk_live_[0-9a-zA-Z]{24,}" # Stripe Live Publishable Key
# 手机号/身份证 (中国大陆,按需启用)
# "1[3-9]\d{9}"
# "\d{18}[\dXx]?"
)
进阶:使用 pre-commit 框架
对于团队项目,推荐使用 pre-commit 框架配合专用工具,比手动脚本更强大:
创建一个 .pre-commit-config.yaml 文件:
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
exclude: '\.env\.example|tests/.*'
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: detect-private-key
- id: check-added-large-files
args: ['--maxkb=500']
最佳实践建议
- 基线文件:使用
detect-secrets生成一个基线文件,记录已知的合法敏感信息,避免误报 - 分级策略:
- 硬编码密码/密钥 → 立即阻止
- 内网IP/域名 → 警告但不阻止
- 测试数据 → 白名单过滤
- 输出友好:错误信息要明确告诉开发者:
哪个文件+哪一行+什么类型
注意事项
- 脚本只能检查新增的行,无法检测通过
git mv重命名而内容未变的文件 - 对于大型二进制文件(如 SQLite 数据库、图片等),应使用
git lfs管理,脚本中排除检查 - 定期更新模式库,防御新的泄露风险(如新出现的安全令牌格式)
将这个脚本与 CI/CD 流水线中的扫描结合,可以构建前后端双层防线。