小Cの已经记不起来的博客

Git 工作流中的 数据脱敏 最佳实践

前几天想给一个老项目换个 CI,顺手把仓库重新 clone 下来翻了翻,结果 git log -p 看历史的时候发现,两年前调试的时候把一份带真实数据库密码和 OSS AccessKey 的配置文件直接提交上去了,后面虽然把文件删了,但懂 Git 的都知道,删了不代表没了,历史里全都在,仓库是私有的不假,但看着还是膈应,没准儿哪天 token 泄了或者手一抖把仓库开源了,那就乐子大了...

这里把处理过程和后来加的防护记一下,省得下次又忘。

先换密钥,再谈别的

这个顺序很重要。历史里能抹干净,但如果这个仓库推到过远端、或者有别的协作者 clone 过,就应该当密钥已经泄露了。所以第一件事是去控制台把那个 AccessKey 禁用掉换新的,数据库密码也顺手改了。删历史只是让仓库干净,救不回已经泄出去的密钥。

找出历史里到底藏了什么

先全量搜一遍,别凭记忆:

git grep -i 'password\|access_key\|secret' $(git rev-list --all)

这个命令会把所有提交翻一遍,仓库大的话会有点慢,泡杯茶等会儿。更省心的办法是直接上 gitleaks,这玩意儿内置了一堆正则,专门匹配常见密钥的格式:

gitleaks detect --source . --verbose --report-path leaks.json

跑完看一眼 leaks.json,哪里泄露的、哪个 commit、长什么样,全给你列出来了。

从历史里把数据抹掉

抹历史用 git-filter-repo,官方现在也是推荐这个,git filter-branch 就别碰了,慢得要死还一堆坑。

先写一个替换规则文件,格式是 原内容==>替换成什么:

AKIDEXAMPLE123==>[REDACTED]
OldPassw0rd!==>[REDACTED]

然后找个干净的地方重新 clone 一份再操作(filter-repo 官方建议在 fresh clone 上跑,--force 会把 stash 和未提交的改动全干掉,别问我怎么知道的),执行:

git filter-repo --replace-text replacements.txt --force

跑完过后用 git log -S 'AKIDEXAMPLE123' 再查一遍,查不到就说明干净了。另外它会把 remote 给你摘掉,这是保护机制,自己 git remote add origin 加回来,然后 git push --force --all 强推上去,记得喊所有协作者重新 clone,别让他们哪天把旧历史又推回来。

不想折腾的话,BFG Repo-Cleaner 也能干同样的事,就一条命令,代价是得自己装 Java,看个人喜好吧。

以后别再犯:本地和服务端各一道闸

历史洗干净了,更重要的是别再犯。

第一层,该忽略的先忽略。.env、私钥、本地配置这类文件,进项目第一天就该写进 .gitignore:

.env
*.pem
config/local.*

敏感配置走环境变量,仓库里只放一个 .env.example,里面全是占位符。

第二层,本地提交前自动扫一遍。用 pre-commit 挂上 detect-secrets:

repos:
  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.4.0
    hooks:
      - id: detect-secrets

pre-commit install 装上过后,每次 git commit 都会先扫一遍暂存区,扫出疑似密钥直接拦下来。偶尔有误报,比如测试用的假密钥,git commit --no-verify 跳过就行,但跳之前最好真的确认那是假的。

第三层,服务端兜底。本地 hook 说白了靠自觉,谁电脑上没装都拦不住,所以 CI 里还得再跑一次 gitleaks,拿 GitHub Actions 举例:

name: secrets-scan
on: [push, pull_request]
jobs:
  gitleaks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

fetch-depth: 0 这行别漏,不然只扫得到当前这一次提交。另外如果你用的是 GitHub,仓库设置里的 Push protection 记得打开,扫到已知格式的密钥会直接拒绝推送,等于多了一道不靠自觉的闸。

最后

这套东西说穿了不复杂:密钥泄露先换掉,历史用 filter-repo 洗,本地和服务端各扫一遍。麻烦是麻烦了点,但比起哪天在公网上看到自己的 AccessKey,这点麻烦真不算什么。

评论

还没有评论。

发表评论

提交后评论将经过自动审核,审核通过后公开展示。

未在播放