Caloogy 文章
English

秘密扫描:别把密钥推到 GitHub

日期
2025 年 9 月 11 日
系列
基础设施
阅读
3 分钟
主题
InfraSecret scanningGitGithub

一句话版本

把 API 密钥、数据库密码、私钥提交进代码仓库,是最常见、也最容易避免的安全事故之一。一旦推送到公开仓库,自动化的扫描机器人往往几分钟内就会发现并开始利用。更麻烦的是,Git 会记住一切:删掉文件再提交,密钥仍然躺在历史记录里。 对策分三道:提交前用钩子拦截,推送时由平台拦截,事后持续扫描。而一旦泄露,唯一可靠的补救是立即轮换密钥。

全文分三层:

  1. 通俗理解:把钥匙忘在了公共留言板上
  2. 实际用处:Uber、Toyota 事件,GitHub 推送保护
  3. 原理与工程要点:怎么识别密钥、三道防线、泄露后的处理流程

第一层:通俗理解

1.1 钥匙忘在了公共留言板上

你把家门钥匙的照片贴在了小区的公共留言板上,几分钟后发现了,赶紧撕掉。

但是:

这时唯一的办法是换锁。公开 Git 仓库就是这样的留言板。

1.2 为什么总有人犯


第二层:实际用处


第三层:原理与工程要点

3.1 怎么识别密钥

方法 说明
固定格式 很多服务的密钥有固定前缀和长度,如 AWS 访问密钥以 AKIA 开头、GitHub 令牌以 ghp_ 等开头、私钥文件以 -----BEGIN ... PRIVATE KEY----- 开头。准确率高
高熵字符串 一段看起来很随机的长字符串可能是密钥。误报较多
上下文 变量名叫 password、secret、token 的赋值
验证 部分工具会尝试用发现的密钥调用服务商接口,确认它是否仍然有效,帮助排定处理优先级

服务商设计带前缀的密钥格式,本身就是为了让扫描更准确。

3.2 三道防线

防线 工具 作用
提交前 gitleaks、detect-secrets 等作为 pre-commit 钩子 在本地就拦住,密钥从未进入历史
推送时 代码托管平台的推送保护 即使本地没装钩子也能拦住
事后 平台的秘密扫描、trufflehog 等扫描全部历史 发现已经存在的泄露

再加上源头措施:

3.3 泄露之后的处理流程

有

没有

发现密钥泄露

立即轮换:作废旧密钥、生成新密钥

检查泄露期间的使用记录

有异常使用?

按事故处理:评估影响、通知相关方

记录并结案

清理历史(可选)

复盘:为什么三道防线都没拦住

要点:

  1. 轮换是第一步,也是唯一可靠的一步。删除提交、改写历史、把仓库设为私有都不够:密钥可能已经被复制,仓库的分叉、缓存、镜像里也还有;
  2. 改写 Git 历史(如 git filter-repo)可以减少日后被再次发现的机会,但前提是已经轮换;
  3. 检查服务商的访问日志,看泄露窗口内是否有异常调用;
  4. 复盘并补上缺失的防线(见《事故响应与复盘》)。

3.4 减小泄露的影响

即使做得再好,泄露也可能发生。提前做好这些,能让泄露的影响小很多:


总结

层次 要点
风险 公开仓库里的密钥几分钟内就可能被利用;Git 历史记住一切
识别 固定前缀格式最准;高熵和上下文作为补充
防线 提交前钩子、推送保护、事后扫描
泄露后 立即轮换;删除记录不够;查日志;复盘