本文目录导读:

Git 钩子脚本可以通过编写 Shell、Python、Ruby 或任何可执行脚本,在特定事件(如提交、推送)发生时自动执行安全检查,从而实现“安全门禁”功能。
以下是几种常见的实现方式与关键检查点:
检查常见的安全漏洞与敏感信息泄漏
这是最常见的门禁场景,防止密码、API密钥、私钥、数据库连接串被提交到仓库。
脚本位置: pre-commit(提交前运行)
核心检查逻辑(以 Bash 为例,使用 grep):
#!/bin/bash
# .git/hooks/pre-commit
# 定义高危模式列表
SENSITIVE_PATTERNS=(
"-----BEGIN RSA PRIVATE KEY-----"
"-----BEGIN OPENSSH PRIVATE KEY-----"
"password\s*=\s*['\"][^'\"]+"
"api_key\s*=\s*['\"][^'\"]+"
"secret\s*=\s*['\"][^'\"]+"
"AKIA[0-9A-Z]{16}" # AWS Access Key
"sk-[0-9a-zA-Z]{32,}" # OpenAI Key
)
# 只检查暂存区(staged)的文件,避免扫描整个工作区
for file in $(git diff --cached --name-only --diff-filter=ACM); do
# 跳过二进制文件
if [[ "$file" == *.png || "$file" == *.jpg || "$file" == *.exe ]]; then
continue
fi
# 循环检查每个模式
for pattern in "${SENSITIVE_PATTERNS[@]}"; do
if git show ":$file" | grep -qE "$pattern"; then
echo "❌ 检测到敏感信息:$file 中包含疑似密钥或密码 (模式: $pattern)"
echo " 请使用 .gitignore 或 git filter-branch 移除后重试。"
exit 1
fi
done
done
echo "✅ 敏感信息检查通过"
exit 0
代码质量与安全规范检查
检查代码风格、潜在的安全漏洞(如 SQL 注入、XSS)。
脚本位置: pre-commit 或 pre-push
实现思路:
# 示例:对 Python 代码使用 Bandit 进行安全检查
for file in $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.py$'); do
# 只检查 staged 版本
git show ":$file" > /tmp/check_temp.py
if ! bandit -q /tmp/check_temp.py; then
echo "❌ 文件 $file 存在安全风险"
rm /tmp/check_temp.py
exit 1
fi
rm /tmp/check_temp.py
done
# 对 JavaScript 使用 ESLint 安全规则
for file in $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.js$'); do
if ! npx eslint --rule 'no-eval: error' "$file"; then
echo "❌ $file 包含 eval() 等高风险代码"
exit 1
fi
done
检查分支合并策略(Push 门禁)
防止强制合并到受保护分支,或检查 Commit Message 格式。
脚本位置: pre-push(推送前运行)
#!/bin/bash
# .git/hooks/pre-push
# 解析推送的目标分支
while read local_ref local_sha remote_ref remote_sha
do
# 只检查推送到 main/master 的分支
if [[ "$remote_ref" == "refs/heads/main" || "$remote_ref" == "refs/heads/master" ]]; then
echo "🔒 检查推送到 $remote_ref 的分支..."
# 获取提交信息
for commit in $(git rev-list $remote_sha..$local_sha 2>/dev/null); do
msg=$(git log --format=%B -n1 $commit)
# 检查 commit message 是否包含 JIRA 工单号
if ! echo "$msg" | grep -qE "^(feat|fix|docs|style)\([^)]+\):\s\[JIRA-\d+\]"; then
echo "❌ 提交 $commit 的 message 不符合规范:需要包含JIRA工单号"
echo " 规范格式: feat(模块): [JIRA-123] 描述内容"
exit 1
fi
# 检查是否包含 TODO/FIXME 标签
if echo "$msg" | grep -qiE "(TODO|FIXME|HACK|XXX)"; then
echo "⚠️ 警告:提交 $commit 包含 TODO/FIXME"
# 可改为 exit 1 来强制拦截
fi
done
fi
done
echo "✅ Push 安全检查通过"
exit 0
依赖安全审计(Pre-push 场景)
检查项目中是否有已知漏洞的依赖包。
#!/bin/bash
# 在 pre-push 中检查
if [ -f "package.json" ]; then
npm audit --audit-level=high
if [ $? -ne 0 ]; then
echo "❌ 项目存在高危漏洞依赖,请先修复"
exit 1
fi
fi
if [ -f "requirements.txt" ]; then
# 使用 safety 检查 python 依赖
safety check -r requirements.txt
if [ $? -ne 0 ]; then
echo "❌ 存在已知漏洞的Python依赖"
exit 1
fi
fi
文件类型与大小门禁
防止超大文件(如日志、压缩包)或不合规文件类型被提交。
#!/bin/bash
MAX_SIZE_MB=10
ALLOWED_EXTENSIONS="\.(py|js|ts|jsx|tsx|go|java|rb|cpp|h|json|yaml|yml|md|txt|html|css)$"
for file in $(git diff --cached --name-only --diff-filter=ACM); do
# 检查文件大小
blob_size=$(git cat-file -s :"$file")
if [ $blob_size -gt $((MAX_SIZE_MB * 1024 * 1024)) ]; then
echo "❌ $file 超过 ${MAX_SIZE_MB}MB 限制 (实际 ${blob_size} 字节)"
exit 1
fi
# 检查扩展名
if [[ ! "$file" =~ $ALLOWED_EXTENSIONS ]]; then
echo "⚠️ 警告:$file 是不推荐提交的文件类型"
# 可根据策略改为 exit 1 拦截
fi
done
进阶方案:使用专用工具集成
手动编写脚本容易遗漏复杂场景,推荐集成专业工具:
| 工具 | 用途 | 集成方式 |
|---|---|---|
| Talisman | 检测敏感信息、凭据 | pre-commit hook |
| gitleaks | 检测硬编码密钥 | pre-commit 或 pre-push |
| husky (JS项目) | 管理 Git hooks,集成 lint-staged | pre-commit |
| pre-commit (框架) | 统一管理多种检查 | .pre-commit-config.yaml |
使用 pre-commit 框架的示例配置文件:
# .pre-commit-config.yaml
repos:
- 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=10240']
- repo: https://github.com/gitleaks/gitleaks
rev: v8.16.1
hooks:
- id: gitleaks
安装与激活钩子
# 方法1:直接复制脚本到 .git/hooks/ cp my-pre-commit.sh .git/hooks/pre-commit chmod +x .git/hooks/pre-commit # 方法2:使用 pre-commit 框架(推荐) pip install pre-commit # 或 brew install pre-commit pre-commit install # 自动生成钩子文件
最佳实践建议
- 只检查暂存区文件:使用
git diff --cached而非检查整个工作目录,避免误报和性能问题。 - 区分警告与拦截:低风险问题(如 TODO 标签)输出黄色警告,高风险问题(如密钥泄漏)输出红色错误并
exit 1。 - 跳过机制:支持
--no-verify参数临时跳过(紧急情况),但应在团队规范中限制使用。 - 性能优化:检查大量文件时,使用
git diff --name-only --diff-filter=ACM缩小范围,只检查新增/修改的文件。 - CI 双重保障:本地钩子可能被绕过,务必在 CI/CD 中部署相同的安全扫描作为最终防线。
通过以上方法,Git 钩子可以成为团队代码安全的“第一道防线”,在代码提交或推送前自动拦截风险,无需依赖事后人工审查。