AI活用

gitleaks 显示“no leaks”,却还漏了2处:公开仓库前的密钥检查步骤

gitleaks 显示“no leaks”,却还漏了2处:公开仓库前的密钥检查步骤

Photo: gitleaks(GitHub) (紹介目的で使用) via github.com

早上好,我是まさきん。

我正在准备把家里用的自动化脚本放到 GitHub 的公开仓库上。在排查敏感信息时,扫描工具明明说“没有泄露”,结果还是剩下了2处。这里把整个检查流程记录下来。

※以下为文章发布时的信息,最新条件请以官方网站为准。

POINT
  • gitleaks 通过正则表达式和熵值,找出 API 密钥这类“能从格式上认出来的密钥”
  • 格式上没有特征的硬编码值,有可能从扫描工具眼皮底下溜过去
  • 用旧 .env 里的实际值对整个仓库做比对,就能把漏网之鱼找出来
  • 公开仓库会免费自动运行 GitHub 的 Secret Scanning
  • 密钥一旦进入历史记录,要先吊销并重新签发密钥,再考虑改写历史

显示“no leaks”却还剩下的2处

我家里跑着各种各样的自动化工具。配置文件(.env)分散成14个,密钥文件也到处都是。我把它们统一成了一个配置文件(41个键)加一个 credentials 文件夹,代码这边大约70个文件的引用也都改了过来。

假设把整理好的东西提交到 git,我先跑了一遍 gitleaks,结果是“no leaks”。

不过保险起见,我又拿旧 .env 里的实际值逐一比对了一遍。结果找出了2处 gitleaks 没发现的硬编码:一处是局域网内设备的访问码,另一处是和个人文件名有关的值。

这两个值看起来都不像 API 密钥。从工作原理来看,扫描工具漏掉它们其实也不奇怪。

gitleaks 是怎么找出密钥的

gitleaks 是一款专门查找密码、API 密钥等敏感信息的工具,可以检查 git 历史、文件以及标准输入。

检测的核心是“规则”。每条规则都带有正则表达式,用来匹配各个服务的令牌格式。官方仓库的默认配置里收录了200多条规则。

另一个维度是熵值,也就是衡量一串字符有多随机的数值。通用 API 密钥的规则,就是结合 key 之类的关键词和值的熵来判断的。

整理一下大致如下:

类型gitleaks 能否发现原因
主流服务的 API 密钥、令牌容易发现有固定的前缀或格式
password= 后面跟着的长随机字符串容易发现关键词和熵值都能命中
只有几位数字的短访问码不易发现格式和随机性都没什么特征
内部 URL、主机名、文件名不易发现和普通字符串难以区分
没有键名的硬编码值不易发现缺少可作线索的关键词

安装和基本命令

官方 README 介绍了通过 Homebrew、Docker 安装,或用 Go 从源码构建。Mac 上这样装就行:

brew install gitleaks

要注意的是命令名。旧文章里常见的 detect 和 protect,在 v8.19.0 已被弃用。现在基本用下面3种模式:

命令检查对象适用场景
gitleaks gitgit 历史(git log -p 的差异)追溯检查已提交的全部内容
gitleaks dir目录或文件检查还没放进 git 的文件
gitleaks stdin标准输入直接检查其他命令的输出

常用写法如下:

# 检查当前仓库的历史
gitleaks git -v

# 在放进 git 之前,检查准备公开的文件夹
gitleaks dir -v ./my-scripts

发现泄露时退出码为1,什么都没有则为0,可以在脚本里拿来做拦截判断。

误报的处理

测试用的假数据之类,有时会触发误报。官方 README 给出了3种办法:

  1. 在该行加上 gitleaks:allow 注释
  2. 把报告里的 Fingerprint 写进 .gitleaksignore,只忽略这一条
  3. 在配置文件 .gitleaks.toml 的 allowlist 里,按路径或正则整体排除

allowlist 在 v8.25.0 改成了 [[allowlists]] 的写法,照抄旧配置示例时要留意。

我个人觉得用 Fingerprint 逐条忽略比较稳妥。按路径整体排除的话,以后真有密钥混进来也发现不了。

用 pre-commit 在提交前拦截

作为日常的防线,gitleaks 也可以作为 pre-commit 钩子使用。

  1. 安装 pre-commit
  2. 在仓库根目录的 .pre-commit-config.yaml 写入以下内容
  3. 执行 pre-commit autoupdate 和 pre-commit install
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.24.2
    hooks:
      - id: gitleaks

GitHub 的 Secret Scanning 和 Push Protection

GitHub 这边也有查找密钥的机制。在公开仓库中的情况如下:

功能公开仓库中的情况作用
Secret Scanning免费自动运行检查所有分支的 git 历史,发现后发出通知
Push protection for users按账户默认开启拦截向公开仓库推送含密钥的内容
Push protection for repositories需要 GitHub Secret Protection按仓库拦截推送

Secret Scanning 也会检查 Issue 和 Pull Request 的正文。如果发现合作服务商的密钥,还会通知对应的服务商。

话虽如此,这两者基本上针对的都是“能从格式上认出来的密钥”。把没有格式特征的值也全交给它们,恐怕有点冒险。

把 .env 拆出去,再配合 .gitignore

最有效的办法,就是不把密钥写进代码。GitHub 官方文档也推荐使用环境变量。

我这次的统一整理也是这个思路。公开时的结构大致如下:

文件是否放进仓库内容
.env不放真实的值
.env.example放键名,以及假值或说明
.gitignore放排除 .env 和 credentials 文件夹的设置
credentials 文件夹不放密钥文件等

放一个 .env.example,就能公开需要哪些键,同时把值藏起来。

不过 .gitignore 有个坑。正如 git 官方文档所说,它对已经被跟踪的文件不起作用。提交过一次的文件,需要用 git rm --cached 取消跟踪。

和盘点工具一样,把通信费这类固定支出也盘点一遍,整体开销可能会更清楚。

无需签约也能获得100积分的资费模拟 用乐天移动重新审视手机费

点击后会跳转到乐天登录页面,登录后即可看到活动内容。

用实际值比对的自制检查

这是这次最想分享的部分。扫描工具是按“格式”去找的,所以我再补上一种按自己手里的“值”去找的方法:检查旧 .env 里的值有没有出现在仓库中。

  1. 从旧 .env 中只取出值的部分,做成每行一个值的文件
  2. 去掉空行,以及太短容易误伤的值(如 true 或 1)
  3. 值列表放在仓库外面
  4. 用 grep -F 按固定字符串(而非正则)进行比对
  5. 对 git 历史也做同样的比对

假设值列表放在 ~/private/values.txt,示例如下:

# 比对整个工作区(排除 .git)
grep -rnF -f ~/private/values.txt --exclude-dir=.git .

# 比对历史中的所有提交
git grep -nF -f ~/private/values.txt $(git rev-list --all)

加上 -F 后,含特殊符号的值也会被当作普通字符串查找。注意值列表里如果有空行,会匹配到每一行。

CHECK

值列表要放在“不会公开的地方”。比对完之后删掉,或者放回加密的位置会更安心。

替换脚本搞出了重复替换

动手过程中还踩了一个坑,发生在用替换脚本改写约70个文件的引用时。

有3处新字符串里包含了旧字符串。比如把“config”替换成“config_shared”这种情况,替换跑两遍就会变成“config_shared_shared”。

我先全部还原,再重新做了一遍。教训很简单:替换之前,先确认“新字符串里有没有包含旧字符串”。如果包含,最好加上边界条件、只替换一次。

重做之后,做了加载确认的18个文件全部正常。

密钥进入历史后的处理顺序

万一把密钥提交了,顺序很重要。GitHub 官方文档要求首先吊销并重新签发密钥(轮换)。

顺序要做的事原因
1吊销并重新签发密钥或密码旧值失效后,损失就到此为止
2把代码改成从 .env 读取避免把新值又硬编码进去
3必要时用 git filter-repo 改写历史从历史中清除旧值
4强制推送,必要时联系 GitHub 支持清除缓存和 Pull Request 中的引用

官方文档指出,有时仅做轮换就足够了。因为改写历史会改变提交哈希,而且残留在 fork 里的内容也删不掉。

改写历史用的工具是 git filter-repo,需要支持 --sensitive-data-removal 的版本(2.47及以上)。替换值的写法如下:

git-filter-repo --sensitive-data-removal --replace-text ../passwords.txt
注意

只要在公开仓库里出现过一次的密钥,就应当默认已经被别人拿到了。官方给出的顺序是:先吊销密钥并换成新的,再去清理历史。

常见的坑

第一条就是我这次的经历。扫描工具非常靠得住,但它看的只是“格式”。和按值比对结合起来用,会更放心一些。

不光定下规则、还要实际数一数来确认的话题,我在数了164个任务后发现的事里也写过。检查密钥大概也是同样的道理。

开始之前要确认的事

我的公开仓库计划,目前还在进行中。

常见问题

Q. gitleaks 显示“no leaks”,就可以放心公开了吗?

对于能从格式上认出来的密钥,基本可以放心。但短代码或内部文件名之类有可能检测不到,建议同时用值列表做比对。

Q. gitleaks detect 和 gitleaks git 有什么区别?

detect 是在 v8.19.0 被弃用的旧命令。现在检查历史用 git,检查文件夹用 dir。旧命令仍然能用,但不会出现在帮助信息里。

Q. 个人的公开仓库也能用 Secret Scanning 吗?

可以。官方文档写明,公开仓库会免费自动运行。除了所有分支的历史,Issue 和 Pull Request 的正文也在检查范围内。

Q. Push Protection 需要自己设置吗?

按账户生效的 Push protection for users 默认是开启的,会拦截向公开仓库推送含密钥的内容。可以在设置的“Code security”里查看状态。

Q. 在 .gitignore 里写上 .env 就够了吗?

如果还没提交过,这样就不会被跟踪了。但对已经被跟踪的文件不起作用。需要先用 git rm --cached 移除,再确认历史里有没有残留。

Q. 不小心提交了密钥,第一步该做什么?

先吊销并重新签发密钥或密码。至于要不要改写历史,之后再判断。

参考的官方资料

总结

gitleaks 在查找能从格式上认出来的密钥方面,确实非常可靠。但另一方面,没有格式特征的值,可能会藏在“no leaks”的背后。

所以,扫描工具和按值比对结合起来用比较好。就像排查重复订阅一样,多一个视角,看到的东西就不一样。在按下公开按钮之前,不妨先打开手边的 .env 看一眼。

无需签约也能获得100积分的资费模拟 查看乐天移动的资费方案

点击后会跳转到乐天登录页面,登录后即可看到活动内容。

本文包含联盟营销广告。如果您通过本站链接申请相关商品或服务,我们可能会从合作企业获得报酬。此外,运营者是乐天集团的员工,也可能通过员工推荐计划获得报酬。文章内容与评价均基于运营者的真实体验与调查完成,与是否存在广告无关,但请您在阅读前了解上述关系。详情请参阅免责声明与联盟营销说明。 免责声明与联盟营销说明

本文包含机器翻译内容。正式条件请以乐天移动官方网站的多语言页面为准。

如果您对乐天移动的通信区域·信号状况有疑问,可以通过官方的 电波改善调查申请表 进行咨询。

ABOUT THE AUTHOR
まさきん

乐天集团员工·数字营销人(持有FP资格)

40岁出头,双职工家庭、四个孩子的父亲。在乐天集团担任数字营销工作的同时,也活用理财规划师(FP)资格,专注于家庭理财与资产配置。

查看简介

相关文章

RELATED
Gemini(Google AI Pro)家庭共享最多5名家人|设置步骤与共享范围 AI活用

Gemini(Google AI Pro)家庭共享最多5名家人|设置步骤与共享范围

Google AI Pro除管理员外最多可与5名家人共享。Gemini App和存储空间可以共享,YouTube Premium Lite仅限管理员,Flow的上限由全家分摊。本文根据官方帮助整理了设置步骤和儿童账号的处理方式。

2026.10.13 · 阅读约9分钟
AI订阅扣款日与记账对不上的3个原因|Claude升级后扣款日会改变 AI活用

AI订阅扣款日与记账对不上的3个原因|Claude升级后扣款日会改变

Claude在月中升级到Max时,计费周期会重置,当天成为新的扣款日。美元换算日元的汇率在数据到达发卡公司时确定,账单和记账App的同步也会晚几天。本文整理了以收据邮件为准来确定月份的5个步骤。

2026.10.13 · 阅读约10分钟
把freee会计的未处理明细改成每月一次的核销班次:每月5日7:30、分3类、最多15条交给人处理的设计 AI活用

把freee会计的未处理明细改成每月一次的核销班次:每月5日7:30、分3类、最多15条交给人处理的设计

freee会计里有大约18条未处理明细,连续6次每周检查都原封不动地留着。这里整理一下每月5日早上7:30在家里的Mac上运行的核销班次的设计,以及“能确定的部分每月合并成1个任务、拿不准的明细逐条交给人、上限15条”的界线。

2026.10.12 · 阅读约11分钟
转到乐天移动,最高可获14,000积分 无需签约也能获得100积分的资费模拟 →
立即申请 →