Git钩子脚本如何检查安全门禁

wen 实用脚本 1

本文目录导读:

Git钩子脚本如何检查安全门禁

  1. 检查常见的安全漏洞与敏感信息泄漏
  2. 代码质量与安全规范检查
  3. 检查分支合并策略(Push 门禁)
  4. 依赖安全审计(Pre-push 场景)
  5. 文件类型与大小门禁
  6. 进阶方案:使用专用工具集成
  7. 安装与激活钩子
  8. 最佳实践建议

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-commitpre-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-commitpre-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       # 自动生成钩子文件

最佳实践建议

  1. 只检查暂存区文件:使用 git diff --cached 而非检查整个工作目录,避免误报和性能问题。
  2. 区分警告与拦截:低风险问题(如 TODO 标签)输出黄色警告,高风险问题(如密钥泄漏)输出红色错误并 exit 1
  3. 跳过机制:支持 --no-verify 参数临时跳过(紧急情况),但应在团队规范中限制使用。
  4. 性能优化:检查大量文件时,使用 git diff --name-only --diff-filter=ACM 缩小范围,只检查新增/修改的文件。
  5. CI 双重保障:本地钩子可能被绕过,务必在 CI/CD 中部署相同的安全扫描作为最终防线。

通过以上方法,Git 钩子可以成为团队代码安全的“第一道防线”,在代码提交或推送前自动拦截风险,无需依赖事后人工审查。

抱歉,评论功能暂时关闭!