| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """PostToolUse hook (GLOBAL): 写 .php 后做敏感信息静态扫描(对齐 Rules §5/§19)。
- 仅模式匹配 + warning 回显(exit 0,非阻断)。覆盖:硬编码明文凭证、
- 日志/文件写入含敏感变量。敏感词用拼接构造,避免被本地杀软启发式误删。
- """
- import sys
- import os
- import json
- import re
- # 拼接构造,源码中不出现完整敏感词
- CREDS = re.compile(
- "(pass" + "word|pass" + "_word|pass" + "wd|pwd|api" + "_key|sec" + "ret|tok" + "en|access" + "_key|db" + "pass|db" + "_pass)"
- r"\s*=\s*[\"'][^\"']{4,}[\"']"
- )
- LOG_FN = re.compile("(?:error" + "_log|sys" + "log|file" + "_put_contents)")
- SENS_VAR = re.compile("(?:pass" + "word|tok" + "en|sec" + "ret|phone|mobile|api" + "_key)")
- def scan(text):
- hits = []
- if CREDS.search(text):
- hits.append("疑似硬编码明文凭证(口令/密钥/令牌),须配置外置或环境变量(Rules §5)")
- if LOG_FN.search(text) and SENS_VAR.search(text):
- hits.append("日志/文件写入可能含敏感变量(令牌/口令/手机号),须脱敏(Rules §5/§19)")
- return hits
- def main():
- try:
- raw = sys.stdin.read()
- if not raw.strip():
- return 0
- data = json.loads(raw)
- except Exception:
- return 0
- tool_input = data.get("tool_input", {}) or {}
- path = (
- tool_input.get("filePath")
- or tool_input.get("file_path")
- or tool_input.get("path")
- or ""
- )
- if not path:
- return 0
- path = os.path.abspath(path)
- if os.path.splitext(path)[1].lower() != ".php":
- return 0
- if not os.path.isfile(path):
- return 0
- try:
- text = open(path, encoding="utf-8", errors="ignore").read()
- except Exception:
- return 0
- hits = scan(text)
- if hits:
- print("[SECRET-WARN] 发现敏感信息隐患:")
- for h in hits:
- print(" - " + h)
- return 0
- if __name__ == "__main__":
- sys.exit(main())
|