From 8f97e349009fad35197f29d3a4b3a7f72b23839d Mon Sep 17 00:00:00 2001 From: Lixi20 Date: Mon, 14 Sep 2026 15:57:05 +0800 Subject: [PATCH] =?UTF-8?q?fix(security):=20=E5=87=AD=E8=AF=81=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E8=A1=A5=20AI=20=E6=9C=8D=E5=8A=A1=E5=95=86=E5=AF=86?= =?UTF-8?q?=E9=92=A5=E5=BD=A2=E6=80=81=E4=B8=8E=20api=5Fkey=20=E8=B5=8B?= =?UTF-8?q?=E5=80=BC=EF=BC=88ADR-021=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M4 将引入 AI 服务商凭证,而现行规则表对其完全不覆盖。夹具实测: 5 种真实形态(ANTHROPIC_API_KEY=sk-ant-…、OPENAI_API_KEY=sk-proj-…、 openai_api_key: "sk-…"、api_key = "…"、api-token: "…")修复前全部 漏网退出 0,修复后全部拦下。 - 新增 AK-ANTHROPIC(sk-ant-)、AK-OPENAI(sk- / sk-proj- / sk-svcacct-) - KEY-ASSIGN 扩至 api[-_]?(key|secret|token) 与 auth[-_]?token (原模式只认 access_key / secret_key 两族) - ALLOW 补 x{3,}:使「讲解规则的文档」不被规则自身拦下 - git-workflow.md 覆盖面概述同步(细节仍以脚本规则表为唯一来源) 验证:占位夹具仍放行;三仓 --all 全绿零误报;三仓副本 md5 同构 640994c12bfa78b4512e872d709ed685;mkdocs --strict exit 0。 依据 iteration-4/08 §漏检清单(决策 G),须先于任何 AI key 落地。 Co-Authored-By: Claude Opus 5 (1M context) --- docs/development/git-workflow.md | 2 +- scripts/check-secrets.sh | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/development/git-workflow.md b/docs/development/git-workflow.md index 7d1a610..7cc361c 100644 --- a/docs/development/git-workflow.md +++ b/docs/development/git-workflow.md @@ -47,7 +47,7 @@ feat: 迁移珊瑚橙主题体系并新增认证基础组件(ADR-005) 之后每次 `git commit` 自动扫描暂存区内容与文件名。注意 `core.hooksPath` 会整体接管 hooks 目录(当前三仓无其他自定义 hook)。`git commit --no-verify` 可绕过,但仅限确认误报时使用——CI 兜底仍会拦。 2. **CI 兜底(强制)**:三仓 `ci.yml` 在 checkout 后的首个 step 运行同一脚本的 `--all` 模式,对全部已跟踪文件扫描(本次 push 变更文件的超集),命中即红,禁止合入。 -规则覆盖(细节以脚本内规则表为准,不在文档重复维护,避免两处漂移):云厂商 AccessKey 形态(AWS/腾讯云/阿里云前缀)、MinIO 默认凭证、独立成行的私钥 PEM 头、access/secret key 与 JWT/签名密钥的实值赋值、配置类文件中非 `${}` 注入形态的数据库口令、`.env`/credentials/密钥导出 CSV 文件本体误入版本库。允许清单:`${}` 注入形态、占位值(changeme、your-xxx、`<占位>` 等)与明显示例值——配置真实值仍只允许存在于被 gitignore 的文件中,占位只进 `.sample`。 +规则覆盖(细节以脚本内规则表为准,不在文档重复维护,避免两处漂移):云厂商 AccessKey 形态(AWS/腾讯云/阿里云前缀)、**AI 服务商密钥形态(Anthropic `sk-ant-`、OpenAI `sk-` / `sk-proj-` / `sk-svcacct-`)**、MinIO 默认凭证、独立成行的私钥 PEM 头、access/secret key **与 api key/secret/token、auth token** 与 JWT/签名密钥的实值赋值、配置类文件中非 `${}` 注入形态的数据库口令、`.env`/credentials/密钥导出 CSV 文件本体误入版本库。允许清单:`${}` 注入形态、占位值(changeme、your-xxx、`<占位>`、`xxx` 等)与明显示例值——配置真实值仍只允许存在于被 gitignore 的文件中,占位只进 `.sample`。 手动全量自查:`sh scripts/check-secrets.sh --all`(在仓库根目录执行)。 diff --git a/scripts/check-secrets.sh b/scripts/check-secrets.sh index 90299d2..8256a57 100755 --- a/scripts/check-secrets.sh +++ b/scripts/check-secrets.sh @@ -15,7 +15,9 @@ set -u mode="${1:---all}" # 允许清单:行内出现任一形态即放行(${} 注入、占位值、明显示例值) -ALLOW='\$\{[^}]*\}|\{\{[^}]*\}\}|changeme|change[-_]me|your[-_][a-zA-Z0-9_-]+|<[a-zA-Z0-9 ,_.-]+>|placeholder|example|sample|dummy|fake|redacted|\*\*\*' +# 注:x{3,}(xxx / xxxx…)是本项目文档描述凭证形态时的既有占位约定, +# 放行它使「讲解规则的文档」不会被规则自身拦下(如 iteration-4/08 §漏检清单)。 +ALLOW='\$\{[^}]*\}|\{\{[^}]*\}\}|changeme|change[-_]me|your[-_][a-zA-Z0-9_-]+|<[a-zA-Z0-9 ,_.-]+>|placeholder|example|sample|dummy|fake|redacted|\*\*\*|x{3,}' # 内容扫描跳过:本脚本与 hook 自身(含规则文本,非凭证) SKIP_PATHS='(^|/)scripts/(check-secrets\.sh|hooks/pre-commit)$' @@ -29,9 +31,11 @@ RULES=$(cat <<'EOF' AK-AWS - - AKIA[0-9A-Z]{16} AK-QCLOUD - - AKID[0-9A-Za-z]{16,} AK-ALIYUN - - LTAI[0-9A-Za-z]{12,} +AK-ANTHROPIC - - sk-ant-[A-Za-z0-9_-]{16,} +AK-OPENAI - - sk-(proj-|svcacct-)?[A-Za-z0-9]{20,} MINIO-DEFAULT i - minio[-_.]?admin PRIVATE-KEY - - ^[[:space:]]*-----BEGIN [A-Z ]*PRIVATE KEY-----[[:space:]]*$ -KEY-ASSIGN i - (access[-_]?key(_?id)?|secret[-_]?(access[-_]?)?key)["']?[[:space:]]*[:=][[:space:]]*["']?[A-Za-z0-9+/=_-]{8,} +KEY-ASSIGN i - (access[-_]?key(_?id)?|secret[-_]?(access[-_]?)?key|api[-_]?(key|secret|token)|auth[-_]?token)["']?[[:space:]]*[:=][[:space:]]*["']?[A-Za-z0-9+/=_-]{8,} JWT-SECRET i - (jwt[-_.]?secret|signing[-_]?key|token[-_]?secret|hmac[-_]?(key|secret))["']?[[:space:]]*[:=][[:space:]]*["']?[A-Za-z0-9+/=_-]{8,} DB-PASSWORD i \.(ya?ml|properties|toml|conf|ini)(\.sample|\.example)?$ (password|passwd|pwd)["']?[[:space:]]*[:=][[:space:]]*["']?[^[:space:]"'$]{6,} EOF