安全
凭据泄露:现在该怎么办
密钥、令牌或密码被发送到了示例域名。请撤销并替换它们,本指南附有常见服务提供商撤销页面的直接链接。
指南 · 安全
密钥、令牌或密码被提交到了某个 commit 中。在新的 commit 中删除该文件并不能解决问题:旧的 commit 仍然包含它,存在于每个克隆和每个 fork 中。本指南介绍正确的顺序:先撤销,再重写历史记录,然后清理托管平台,并确保不再发生。
即使是在私有仓库中,也应将已提交的机密信息视为已泄露:克隆、fork、CI 日志和备份中可能已经存有副本,而自动扫描工具会在几分钟内发现公开仓库中的新 commit。
在常见服务提供商处撤销密钥的位置,请参阅凭据泄露:现在该怎么办。重写历史记录是在此之后进行的步骤,绝不能代替撤销。
机密信息一旦撤销就不再具有访问权限,GitHub 也指出这可能已经足够。但在以下情况下,仍然值得重写:
重写会改变之后每个 commit 的 ID。协作者需要对自己的工作执行 rebase,未关闭的 pull request 可能会丢失评审意见,commit 签名也会被移除。请与所有相关人员约定时间,并先合并或关闭所有打开的 pull request。
# 哪些 commit 添加或删除了该字符串?
git log --all --oneline -S 'the-secret-value'
# 它出现在哪些文件中?
git grep 'the-secret-value' $(git rev-list --all)
# 扫描整个历史记录中的已知机密信息格式
gitleaks git -v
记下机密信息出现过的每个文件路径,如果文件曾被移动或重命名,也要包括以前的名称。
git-filter-repo 是 GitHub 推荐的工具。请使用 2.47 或更高版本,该版本提供 --sensitive-data-removal 选项,并在全新的克隆中操作。
# 安装(或使用您的包管理器)
brew install git-filter-repo # macOS
pip install git-filter-repo # 任何装有 Python 的环境
git clone https://github.com/YOUR-ORG/YOUR-REPO
cd YOUR-REPO
# 方法 1:从全部历史记录中删除整个文件
git-filter-repo --sensitive-data-removal --invert-paths --path config/secrets.yml
# 方法 2:在所有出现的位置替换机密信息
git-filter-repo --sensitive-data-removal --replace-text ../replacements.txt
替换文件每行列出一个值。默认情况下,每个匹配项都会变成 ***REMOVED***;使用 ==> 可以自行指定替换内容,使用 regex: 则按模式匹配:
# ../replacements.txt(放在仓库之外)
sk_live_51Hx0000000000000000000000
AKIA0000000000000000==>AWS_ACCESS_KEY_ID_REMOVED
regex:password\s*=\s*"[^"]+"==>password = "REMOVED"
使用 git log --all -S 'the-secret-value' 检查结果:应当没有任何输出。然后覆盖远程仓库:
git push --force --mirror origin
如果分支保护会阻止强制推送,需要在此期间暂时关闭。推送之后,重写将无法撤消。
强制推送之后,旧的 commit 仍可通过 pull request、缓存视图和 fork 访问。
grep -c '^refs/pull/.*/head$' .git/filter-repo/changed-refs)以及 git-filter-repo 输出的“First Changed Commit(s)”。只有在轮换凭据无法消除风险时,GitHub 才会提供帮助。在 GitLab、Bitbucket 或自托管服务器上,步骤大致相同;请查阅相应平台的文档,了解它如何删除旧对象和缓存视图。
BFG Repo-Cleaner 是一款较早的、基于 Java 的工具,目前仍被广泛使用。它在镜像克隆上运行,并且默认不改动最新的 commit,因此请先通过一次普通 commit 从当前版本中删除机密信息。
git clone --mirror https://github.com/YOUR-ORG/YOUR-REPO.git
java -jar bfg.jar --replace-text replacements.txt YOUR-REPO.git
cd YOUR-REPO.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push
.env 等文件添加到 .gitignore。git diff --cached,而不是使用 git add . 或 git commit -a。这个密钥是否也发送到了 api.example-petstore.com 这样的占位地址?那么它也已到达一台不受您控制的服务器:配置 API 客户端和 SDK。