本文目录导读:

Git 钩子脚本(通常是 pre-commit 或 commit-msg 钩子)是执行审计策略检查的理想位置,因为它可以在代码进入仓库之前就阻止违规提交。
以下是如何编写 Git 钩子脚本来检查常见审计策略的详细指南和示例。
核心思路
-
选择合适的钩子:
pre-commit: 检查将要提交的(如代码规范、硬编码密码、IP 地址、文件大小等),这是最常见的审计钩子。commit-msg: 检查提交信息(如是否符合“事务ID JIRA-123”的格式、字数限制、禁止的关键词等)。pre-receive/update: 服务端钩子,在中央仓库拒绝不合规的推送,这是最安全的防线。
-
获取被更改的文件列表: 这是审计的基础,需要区分暂存区(Staging Area)和工作区(Working Directory)的文件。
- 暂存区(当前提交):
git diff --cached --name-only --diff-filter=ACM - 所有文件:
git diff --cached --name-status
- 暂存区(当前提交):
-
执行检查逻辑: 遍历文件列表,对特定类型(如
.py,.env,.txt)使用grep、awk、sed等工具或调用外部脚本(Python, Node.js)进行内容检测。 -
返回状态码:
- 0: 通过检查,允许提交。
- 非0: 拒绝提交,并将错误信息打印给用户。
实践案例:pre-commit 钩子审计策略检查
将此脚本保存为项目根目录下 .git/hooks/pre-commit,并赋予执行权限(chmod +x .git/hooks/pre-commit)。
#!/bin/bash
# 防止未初始化变量
set -euo pipefail
# 颜色定义(可选)
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo "${YELLOW}开始审计策略检查...${NC}"
# --- 策略 1:检查提交信息是否包含特定的 JIRA 或 Ticket 号(使用 commit-msg 钩子更佳) ---
# 这里演示如何在 pre-commit 中检查(虽然更推荐在 commit-msg 中做)
COMMIT_MSG=$(cat "$1" 2>/dev/null || echo "no msg")
# 简单演示,实际应放在 .git/hooks/commit-msg 中
# if [[ ! "$COMMIT_MSG" =~ \[JIRA-[0-9]+\] ]]; then
# echo -e "${RED}错误:提交信息必须包含 [JIRA-XXX] 格式的 Ticket 号${NC}"
# exit 1
# fi
# --- 策略 2:检查是否提交了敏感信息(如密码、密钥、IP 地址、信用卡号) ---
# 获取本次提交会被包含的暂存区文件列表(排除已删除的文件)
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
if [[ -z "$STAGED_FILES" ]]; then
echo "${GREEN}没有要提交的文件。${NC}"
exit 0
fi
echo "正在扫描 ${STAGED_FILES} 文件..."
# 定义需要扫描的模式(正则表达式)
SENSITIVE_PATTERNS=(
"password\s*=\s*['\"][^'\"]+['\"]" # 匹配 password = 'xxx'
"api_key\s*=\s*['\"][^'\"]+['\"]" # 匹配 api_key = 'xxx'
"secret\s*=\s*['\"][^'\"]+['\"]" # 匹配 secret = 'xxx'
"token\s*=\s*['\"][^'\"]+['\"]" # 匹配 token = 'xxx'
"AKIA[0-9A-Z]{16}" # AWS Access Key ID
"-----BEGIN (RSA|EC|DSA|OPENSSH) PRIVATE KEY-----" # 私钥
"[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" # 内网 IP(若策略允许则需排除,此处仅示例)
)
# 排除目录(如 node_modules, .git 等,通常钩子只处理暂存文件,所以只需按需过滤)
# 如果暂存文件列表中包含 generated/ 或 dist/ 文件,可以在这里跳过
EXCLUDE_DIRS="(node_modules|dist|build|\.git|vendor)"
VIOLATION_FOUND=false
for FILE in $STAGED_FILES; do
# 检查文件是否存在于暂存区(未被删除)
if ! git ls-files --error-unmatch "$FILE" >/dev/null 2>&1; then
continue
fi
# 检查文件是否在排除目录中(如果文件名包含排除目录则跳过)
if echo "$FILE" | grep -qE "$EXCLUDE_DIRS"; then
continue
fi
# 只检查文本文件(避免二进制文件误报)
if git show :"$FILE" | file - | grep -q "text"; then
# 对每个敏感模式进行检查
for PATTERN in "${SENSITIVE_PATTERNS[@]}"; do
# 从暂存区读取文件内容进行匹配
if git show :"$FILE" | grep -qE "$PATTERN"; then
echo -e "${RED}审计失败:文件 '$FILE' 包含潜在敏感信息!${NC}"
echo -e "${RED}匹配模式: $PATTERN${NC}"
# 显示所在行(只显示前3行以防泄露过多信息)
git show :"$FILE" | grep -nE "$PATTERN" | head -3
echo ""
VIOLATION_FOUND=true
fi
done
fi
done
if [ "$VIOLATION_FOUND" = true ]; then
echo -e "${RED}审计策略检查未通过,提交已被阻止。${NC}"
echo -e "${YELLOW}请移除敏感信息或使用 .gitignore 忽略相关文件。${NC}"
exit 1
fi
# --- 策略 3:检查文件大小限制(防止大文件被提交) ---
MAX_SIZE_MB=5
for FILE in $STAGED_FILES; do
if ! git ls-files --error-unmatch "$FILE" >/dev/null 2>&1; then
continue
fi
# 获取暂存区文件的大小(字节)
SIZE=$(git cat-file -s ":$(git hash-object -w "$FILE" 2>/dev/null)" 2>/dev/null || git cat-file -s ":$FILE" 2>/dev/null || echo 0)
# 更准确的方法:使用 git ls-files 配合 hash
# SIZE=$(git ls-files --stage "$FILE" | awk '{print $4}' | xargs -I {} git cat-file -s {} 2>/dev/null || echo 0)
if [ "$SIZE" -gt $((MAX_SIZE_MB * 1024 * 1024)) ]; then
echo -e "${RED}审计失败:文件 '$FILE' 大小为 $SIZE 字节,超过限制 ${MAX_SIZE_MB}MB。${NC}"
VIOLATION_FOUND=true
fi
done
# --- 策略 4:检查文件权限(如果策略要求特定权限) ---
# 检查 .sh 文件是否有执行权限
for FILE in $STAGED_FILES; do
if [[ "$FILE" == *.sh ]]; then
# 检查暂存区文件的权限(以 100755 或 100644 开头)
MODE=$(git ls-files --stage "$FILE" | awk '{print $1}')
if [[ "$MODE" == 100644 ]] || [[ "$MODE" == "100755" ]]; then
# 如果策略要求 .sh 文件必须有执行权限
echo -e "${YELLOW}警告:脚本文件 '$FILE' 没有执行权限,建议使用 'git update-index --chmod=+x $FILE' 添加。${NC}"
fi
fi
done
# --- 策略 5:检查文件编码(统一要求 UTF-8) ---
for FILE in $STAGED_FILES; do
if git show :"$FILE" | file - | grep -q "text"; then
ENCODING=$(git show :"$FILE" | file - | grep -oP 'charset=\K\S+')
if [[ -n "$ENCODING" ]] && [[ "$ENCODING" != "utf-8" ]] && [[ "$ENCODING" != "us-ascii" ]]; then
echo -e "${RED}审计失败:文件 '$FILE' 编码为 $ENCODING,要求 UTF-8 编码。${NC}"
VIOLATION_FOUND=true
fi
fi
done
# --- 最终结论 ---
if [ "$VIOLATION_FOUND" = true ]; then
echo -e "${RED}审计策略检查未通过,提交已被阻止。${NC}"
exit 1
else
echo -e "${GREEN}所有审计策略检查通过。${NC}"
exit 0
fi
如何安装此钩子
- 保存为
<你的项目>/.git/hooks/pre-commit。 - 赋予执行权限:
chmod +x .git/hooks/pre-commit。 - 💡 推荐使用 Husky 或 pre-commit 框架:
- Husky (For Node.js): 将钩子脚本提交到仓库中,并自动启用。
npx husky add .husky/pre-commit "npm test" - pre-commit (Python): 更强大的框架,支持多语言钩子,配置文件
.pre-commit-config.yaml。pip install pre-commit
- Husky (For Node.js): 将钩子脚本提交到仓库中,并自动启用。
进阶:使用外部审计脚本
对于复杂的策略(如检查代码规范、运行安全扫描工具),最好在钩子中调用外部脚本,而不是全部写在 Bash 里。
在 pre-commit 中调用 Python 审计脚本:
#!/bin/bash
# .git/hooks/pre-commit
echo "正在运行 Python 审计检查..."
# 执行 audit.py 脚本,传入暂存区文件列表
python3 scripts/audit.py $(git diff --cached --name-only --diff-filter=ACM)
# 检查 Python 脚本的返回值
if [ $? -ne 0 ]; then
echo "审计脚本返回错误,阻止提交。"
exit 1
fi
scripts/audit.py 可以执行诸如检测 SQL 注入、硬编码的 API 密钥、自定义正则匹配等复杂逻辑,并直接输出错误消息。
- 核心钩子:
pre-commit用于内容审计,commit-msg用于信息格式审计,pre-receive用于服务器端强制审计。 - 关键命令:
git diff --cached --name-only --diff-filter=ACM获取暂存区改动文件。 - 核心逻辑: 逐文件使用
git show :<file>获取暂存区文件内容,然后用grep等工具匹配策略模式。 - 返回状态:
exit 1拒绝提交,exit 0允许提交。 - 避免问题: 确保钩子脚本是幂等的、高效的(只扫描被改动的文件),并且能处理二进制文件和特殊情况(如文件删除)。务必先测试钩子。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播