代码密钥硬编码泄露风险,git历史密钥泄露排查清理
把数据库密码、API Key 直接写进代码并提交到 Git,等于把服务器钥匙公开挂在门口。
本文面向零基础用户,演示如何用 Gitleaks 排查 Git 历史中的密钥泄露,再用 git filter-repo 彻底清理提交记录,最后完成密钥轮换和结果验证。
为什么硬编码密钥比想象中更危险
很多开发者以为“文件删掉再提交一次”就安全了,但 Git 会永久保留每一次提交记录。
只要密钥曾经进过版本库,任何人通过 git log、git reflog 或第三方工具都能从历史里翻出来。
硬编码密钥最常见的风险有三个:
- 攻击者拿到云厂商 Key 后,直接调用接口创建高价资源或导出数据,造成账单损失和敏感信息外泄。
- 内部人员或离职员工通过旧历史获取密码,绕过正常权限访问生产环境。
- 自动化扫描机器人会持续爬取公开仓库和代码托管平台,发现密钥后可能在几分钟内就发起攻击。
所以排查和清理必须放在“密钥泄露事件”的首要位置,而不是简单改代码。
先用 Gitleaks 全量扫描 Git 历史
Gitleaks 是一款开源的密钥扫描工具,可以扫描当前工作区、提交历史和 diff 中的敏感信息。
准备条件:本地安装 Git,并保证仓库已完整克隆到本地。
安装 Gitleaks 有多种方式,macOS 可用:
brew install gitleaks
Linux 可以下载官方预编译二进制,或使用 Docker:
docker run -v "$PWD:/path" zricethezav/gitleaks:latest detect --source=/path --log-opts="--all" --report-path=/path/report.json
在仓库根目录执行全历史扫描:
gitleaks detect --source . --log-opts="--all" --report-path gitleaks-report.json
扫描完成后,打开 gitleaks-report.json 查看泄露的密钥类型、所在文件和提交哈希。
看到 Leaks Found 提示时,不要急着删除,先记录所有泄露位置的提交 ID 和文件路径。
用 git filter-repo 彻底清理历史提交
清理历史推荐使用 git filter-repo,它比 filter-branch 更快,也更安全。
第一步:备份仓库。
直接复制整个仓库目录,或创建裸备份:
git clone --mirror 原仓库地址 repo-backup.git
第二步:安装 git filter-repo。
它是 Python 脚本,可用 pip 安装:
pip install git-filter-repo
第三步:替换或删除泄露内容。
如果只想把某个密钥替换成占位符,先创建替换规则文件 replace.txt:
AKIAIOSFODNN7EXAMPLE==>REPLACED
然后执行:
git filter-repo --replace-text replace.txt
如果某个文件整个都不该出现,可以按路径删除:
git filter-repo --invert-paths --path config/secret.yml
命令执行后,Git 会重写所有相关提交的哈希,并自动移除 remote 配置。
清理后必须做三件事:轮换、推送、验证
历史清理完成后,很多人直接强制推送,这是错的。先轮换密钥,再推送清理后的仓库,避免旧密钥在推送窗口期继续生效。
- 到云服务商或第三方平台后台,禁用并重新生成泄露的 Access Key、密码或 Token。
- 重新添加远端地址并强制推送:
git remote add origin <你的仓库地址>
git push origin --force --all
git push origin --force --tags
- 验证清理效果。再次运行 Gitleaks 全历史扫描,确认输出结果为
No leaks found。同时用git log --all --oneline抽查旧提交是否已被重写。
注意:
强制推送后,
所有协作者需要用 git fetch --all && git reset --hard origin/main 重新同步,
避免旧历史再次被推上来。
避坑说明与常见疑问
清理 Git 历史最容易被忽略的是 Reflog 和远程备份。
本地执行 filter-repo 后,建议立即 git reflog expire --expire=now --all && git gc --prune=now 清理引用日志。
同时检查仓库平台是否有自动备份、镜像或 Fork,这些位置都可能残留旧提交。
有人会问:直接在 GitHub 上删除仓库重建行不行?
如果泄露仓库已公开且被 fork 或爬取,重建后旧提交仍可能存在于 fork 和缓存中,所以必须联系平台处理,并按泄露事件响应流程评估影响。
还有人问:只删当前文件不重写历史行吗?
不行,旧提交依然能恢复密钥。
最后强调一句:清理历史只是补救措施,密钥轮换才是真正的止血点。
只有两者都完成,代码密钥硬编码泄露风险才能降到可控范围。
如果你正在处理这类问题,建议先按本文步骤完整执行,再根据自己的环境做微调;
遇到异常时优先回看避坑和高频问题部分。