本文目录导读:

我来详细介绍Git钩子脚本扫描密钥泄露的实现方法。
基础密钥扫描钩子脚本
pre-commit钩子示例
#!/bin/bash
# .git/hooks/pre-commit
# 需要扫描的敏感信息模式
PATTERNS=(
"AKIA[0-9A-Z]{16}" # AWS Access Key
"sk_live_[0-9a-zA-Z]{24}" # Stripe Live Secret Key
"-----BEGIN RSA PRIVATE KEY-----" # RSA私钥
"ghp_[a-zA-Z0-9]{36}" # GitHub Personal Access Token
"gho_[a-zA-Z0-9]{36}" # GitHub OAuth Token
"xox[parb]-[a-zA-Z0-9]{1,}-[a-zA-Z0-9]{1,}-[a-zA-Z0-9]{1,}-[a-zA-Z0-9]{1,}" # Slack Token
"password\s*[:=]\s*\S+" # 密码
"secret\s*[:=]\s*\S+" # 密钥
)
echo "🔍 正在扫描密钥泄露..."
# 获取暂存区的文件
STAGED_FILES=$(git diff --cached --name-only)
for FILE in $STAGED_FILES; do
if [ -f "$FILE" ]; then
# 扫描每个文件
for PATTERN in "${PATTERNS[@]}"; do
if grep -qE "$PATTERN" "$FILE"; then
echo "❌ 发现潜在密钥泄露!"
echo "文件: $FILE"
echo "匹配模式: $PATTERN"
grep -nE "$PATTERN" "$FILE"
exit 1
fi
done
fi
done
echo "✅ 密钥扫描通过"
增强版扫描脚本
使用whitelist和更复杂的检测
#!/bin/bash
# .git/hooks/pre-commit-advanced
# 配置
EXCLUDE_PATTERNS_FILE=".secretsignore"
MIN_LINE_LENGTH=10
# 需要排除的文件或目录
EXCLUDE_DIRS=(
"node_modules"
"vendor"
".git"
"*.min.js"
"*.map"
"package-lock.json"
"yarn.lock"
)
# 高熵字符串检测
entropy_check() {
local string="$1"
local length=${#string}
if [ $length -lt 20 ]; then
return 1
fi
# 计算字符分布
local uppercase=$(echo "$string" | grep -o '[A-Z]' | wc -l)
local lowercase=$(echo "$string" | grep -o '[a-z]' | wc -l)
local digits=$(echo "$string" | grep -o '[0-9]' | wc -l)
local special=$(echo "$string" | grep -o '[^a-zA-Z0-9]' | wc -l)
# 高熵判断
if [ $uppercase -gt 5 ] && [ $lowercase -gt 5 ] && [ $digits -gt 3 ]; then
return 0
fi
return 1
}
# 密钥正则模式
SECRET_PATTERNS=(
# API Keys
"(?i)(api[_-]?key|apikey)\s*[:=]\s*['\"][a-zA-Z0-9_-]{20,}['\"]"
"(?i)(secret|token|auth)\s*[:=]\s*['\"][a-zA-Z0-9_-]{20,}['\"]"
# 云服务认证
"aws_access_key_id\s*[:=]\s*\S+"
"aws_secret_access_key\s*[:=]\s*\S+"
# 数据库连接
"mysql://[\w-]+:[\w-]+@"
"postgresql://[\w-]+:[\w-]+@"
"mongodb://[\w-]+:[\w-]+@"
# JWT Tokens
"eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}"
# SSH Keys
"-----BEGIN (RSA|DSA|EC|OPENSSH) PRIVATE KEY-----"
)
# 加载排除规则
load_excludes() {
if [ -f "$EXCLUDE_PATTERNS_FILE" ]; then
while IFS= read -r pattern; do
[[ -z "$pattern" || "$pattern" =~ ^# ]] && continue
EXCLUDE_PATTERNS+=("$pattern")
done < "$EXCLUDE_PATTERNS_FILE"
fi
}
# 检查文件是否应被排除
is_excluded() {
local file="$1"
for dir in "${EXCLUDE_DIRS[@]}"; do
if [[ "$file" == *"$dir"* ]]; then
return 0
fi
done
for pattern in "${EXCLUDE_PATTERNS[@]}"; do
if [[ "$file" == *"$pattern"* ]]; then
return 0
fi
done
return 1
}
# 主扫描函数
scan_secrets() {
local has_secrets=0
# 获取暂存区变更
local staged_files=$(git diff --cached --name-only)
for file in $staged_files; do
if is_excluded "$file"; then
continue
fi
if [ ! -f "$file" ]; then
continue
fi
local current_line=0
# 逐行扫描
while IFS= read -r line; do
((current_line++))
# 跳过空白和注释行
[[ "$line" =~ ^[[:space:]]*$ ]] && continue
[[ "$line" =~ ^[[:space:]]*# ]] && continue
# 1. 正则模式匹配
for pattern in "${SECRET_PATTERNS[@]}"; do
if echo "$line" | grep -qE "$pattern"; then
echo "❌ 文件: $file, 行号: $current_line"
echo " 匹配模式: $pattern"
echo " 内容: $line"
has_secrets=1
fi
done
# 2. 高熵检测
local word
for word in $line; do
if [[ ${#word} -ge 20 ]] && entropy_check "$word"; then
echo "⚠️ 文件: $file, 行号: $current_line"
echo " 发现高熵字符串: ${word:0:20}..."
has_secrets=1
fi
done
done < "$file"
done
return $has_secrets
}
# 执行扫描
echo "🔍 开始高级密钥扫描..."
load_excludes
if scan_secrets; then
echo "✅ 扫描完成,未发现密钥泄露"
exit 0
else
echo ""
echo "❌ 检测到潜在密钥泄露!"
echo " 请移除敏感信息后重新提交"
echo " 如需绕过检查,使用: git commit --no-verify"
exit 1
fi
使用工具集成
集成git-secrets
#!/bin/bash
# .git/hooks/pre-commit-git-secrets
# 安装git-secrets
# brew install git-secrets # macOS
# apt install git-secrets # Linux
# 安装钩子
echo "🔍 使用git-secrets扫描..."
# 添加AWS模式
git secrets --add 'AKIA[0-9A-Z]{16}'
git secrets --add '("|'')?(AWS|aws|Aws)?_?(SECRET|secret|Secret)?_?(ACCESS|access|Access)?_?(KEY|key|Key)'
# 添加自定义模式
git secrets --add 'sk_live_[0-9a-zA-Z]{24}'
git secrets --add 'ghp_[a-zA-Z0-9]{36}'
# 扫描暂存区
git secrets --scan --cached
if [ $? -ne 0 ]; then
echo "❌ git-secrets检测到密钥泄露!"
exit 1
fi
echo "✅ git-secrets扫描通过"
集成truffleHog
#!/bin/bash
# .git/hooks/pre-commit-trufflehog
# 安装truffleHog
# pip install truffleHog3
echo "🔍 使用truffleHog扫描..."
# 扫描暂存区变更
git diff --cached --name-only | while read file; do
if [ -f "$file" ]; then
trufflehog3 file "$file"
if [ $? -ne 0 ]; then
echo "❌ 文件 $file 包含潜在密钥!"
exit 1
fi
fi
done
echo "✅ truffleHog扫描通过"
完整的安装和配置
安装脚本
#!/bin/bash
# install-hooks.sh
HOOKS_DIR=".git/hooks"
# 创建钩子目录
mkdir -p "$HOOKS_DIR"
# 安装主钩子
cat > "$HOOKS_DIR/pre-commit" << 'EOF'
#!/bin/bash
# Pre-commit hook for secret scanning
# 执行扫描
bash .git/hooks/scan-secrets.sh
EOF
# 创建扫描脚本
cat > "$HOOKS_DIR/scan-secrets.sh" << 'SCRIPT'
#!/bin/bash
# 配置
SECRET_PATTERNS=(
"AKIA[0-9A-Z]{16}"
"SK[A-Z0-9]{32}"
"-----BEGIN RSA PRIVATE KEY-----"
"ghp_[a-zA-Z0-9]{36}"
"sk_live_[0-9a-zA-Z]{24}"
"xox[parb]-[a-zA-Z0-9]{1,}-[a-zA-Z0-9]{1,}-[a-zA-Z0-9]{1,}-[a-zA-Z0-9]{1,}"
)
echo "🔍 Scanning for secrets in staged files..."
# Get staged files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
if [ -z "$STAGED_FILES" ]; then
echo "No files staged"
exit 0
fi
FOUND=0
for FILE in $STAGED_FILES; do
if [ -f "$FILE" ]; then
for PATTERN in "${SECRET_PATTERNS[@]}"; do
if grep -qE "$PATTERN" "$FILE"; then
echo "⚠️ WARNING: Found potential secret in $FILE"
echo "Pattern: $PATTERN"
grep -nE "$PATTERN" "$FILE" | sed 's/^/ /'
FOUND=1
fi
done
fi
done
if [ $FOUND -eq 1 ]; then
echo ""
echo "❌ Commit blocked due to potential secrets!"
echo "Remove secrets and try again, or use --no-verify to bypass"
exit 1
fi
echo "✅ No secrets found"
exit 0
SCRIPT
# 设置权限
chmod +x "$HOOKS_DIR/pre-commit"
chmod +x "$HOOKS_DIR/scan-secrets.sh"
echo "✅ Hooks installed successfully!"
配置文件示例
# .secretsignore - 排除规则文件 # 每行一个模式 # 文件级别的排除 *.json *.yaml *.yml *.config.js # 特定目录 test/ fixtures/ examples/ # 特定文件 .env.example config/default.yaml # 特定模式 # 使用正则表达式 .*\.example\.* # 临时允许某些特定密钥 # 格式: 文件名:行号:内容 config/settings.yml:25:# This is a test token: test_value_123
最佳实践
添加全局钩子配置
# 全局钩子配置 git config --global init.templatedir '~/.git-templates' # 创建模板 mkdir -p ~/.git-templates/hooks # 安装钩子到模板 cp pre-commit ~/.git-templates/hooks/
团队部署
// package.json 添加钩子安装脚本
{
"scripts": {
"install-hooks": "bash scripts/install-git-hooks.sh",
"postinstall": "npm run install-hooks"
}
}
使用这些脚本可以有效防止密钥泄露,建议根据团队需求定制扫描规则和排除配置。