Back

当你的 API 密钥泄露到代码仓库时该怎么办

当你的 API 密钥泄露到代码仓库时该怎么办

你把代码推送到 GitHub,几秒钟后才意识到 API 密钥也一起推上去了。也许 GitHub 给你发了警报,也许 GitGuardian 给你发了邮件。无论如何,你现在正在处理前端应用中的密钥泄露问题——而且时间紧迫。

大多数开发者容易犯的关键错误是:从最新提交中删除密钥并不能解决问题。Git 历史记录会保留所有内容。可能已经存在分支副本。自动化机器人会在推送后的几秒钟内扫描公共仓库。

本文将详细介绍当 API 密钥在 GitHub 上泄露时该怎么做,如何区分真正敏感的密钥和公共客户端密钥,以及如何防止再次发生这种情况。

核心要点

  • 立即撤销和轮换已泄露的密钥——清理 Git 历史是次要的,因为密钥已经被泄露了。
  • 区分公共客户端密钥(设计用于浏览器使用)和真正的密钥(需要紧急处理的特权凭证)。
  • Git 历史记录保留所有内容,因此删除提交并不能从分支副本、缓存或现有克隆中删除密钥。
  • 启用 GitHub 的推送保护功能,在包含密钥的提交到达仓库之前将其拦截。
  • 永远不要在前端代码中存储特权密钥——使用服务器端 API 路由或后端代理。

首先,了解你实际泄露了什么

并非所有密钥都具有相同的风险。在你恐慌之前,先识别泄露的是哪种类型的凭证。

公共客户端密钥设计为可见的。限制在特定域名的 Google Maps API 密钥、分析令牌,或明确标记为客户端使用的密钥(如 Next.js 中的 NEXT_PUBLIC_ 或 Vite 中的 VITE_)都是要打包到浏览器包中的。这些仍然应该有使用限制,但泄露并不是灾难性的。

真正的密钥授予特权访问:Stripe 密钥、AWS 凭证、数据库连接字符串,或任何可以读写敏感数据或产生费用的密钥。这些需要立即采取行动。

这种区分很重要,因为你的响应应该与严重程度相匹配。

即时响应:先撤销和轮换

当你泄露了真正的密钥时,清理历史记录是次要的。你的首要任务是轮换已泄露的 API 密钥。

步骤 1:立即撤销已泄露的密钥。 登录到你的 API 提供商的控制面板,删除或禁用已泄露的凭证。不要等到清理完 Git 历史记录——密钥已经被泄露了。

步骤 2:生成具有最小权限范围的新密钥。 应用最小权限原则。尽可能按 IP、域名或特定 API 端点进行限制。

步骤 3:更新你的应用程序。 在应用程序崩溃之前将新密钥部署到你的环境中。

一些云服务提供商会自动禁用他们在公共仓库中检测到的凭证。例如,Google Cloud 默认可以自动禁用已泄露的服务账号密钥。其他提供商,包括 AWS,通常会通知你,但不会始终自动撤销密钥。所有这些提供商都参与了 GitHub 的密钥扫描合作伙伴计划。不要依赖自动化——无论如何都要立即采取行动。

为什么删除提交还不够

Git 永远不会忘记。即使你从当前分支中删除了密钥,它仍然存在于:

  • 通过 git log 可访问的先前提交
  • 在你修复之前创建的分支副本
  • 其他用户或机器人拉取的现有克隆
  • 删除前创建的任何镜像

这就是为什么撤销是第一位的。清理历史记录是遏制,而不是补救。

如果你需要清理历史记录,git filter-repoBFG Repo-Cleaner 等工具可以提供帮助。但要明白,如果你的仓库公开了任何时间,就要假设密钥已被捕获。

GitHub 密钥扫描和推送保护

GitHub 为这个问题提供了一流的保护。密钥扫描和推送保护适用于所有公共仓库,以及通过 GitHub Secret Protection(也包含在 GitHub Advanced Security 中)的私有仓库。

密钥扫描检测仓库中已知的凭证模式,并自动向你和/或提供商发出警报。

推送保护更进一步——它在包含检测到的密钥的提交到达仓库之前就将其拦截。这是目前最有效的预防机制。

在仓库设置中的 Settings → Code security and analysis 下启用这两项功能,或查看关于 GitHub Secret Protection 的官方文档。

前端环境变量陷阱

这是一个困扰许多 React、Vue 和 Next.js 开发者的错误:为客户端使用而添加前缀的环境变量不是密钥

REACT_APP_*NEXT_PUBLIC_*VITE_* 这样的变量会直接打包到你的 JavaScript 中。任何人都可以打开开发者工具找到它们。这些不是隐藏的——它们只是被组织起来了。

如果一个密钥授予特权访问,它就不能存在于前端代码中。就是这样。

前端团队的预防策略

将特权密钥保留在服务器端。 使用 API 路由、无服务器函数或后端代理。你的前端对用户进行身份验证;你的后端持有密钥。

启用推送保护。 这会在错误变成事故之前捕获它们。

使用预提交钩子。gitleaksdetect-secrets 这样的工具可以在本地扫描暂存的更改。

添加 CI 扫描。 在你的流水线中运行密钥检测作为安全网。

严格限制密钥。 即使是公共客户端密钥也应该按域名、IP 或 API 范围进行限制。

结论

当 API 密钥泄露时,速度比完美更重要。先撤销,立即轮换,然后将清理历史记录作为次要步骤。不要混淆公共客户端密钥和真正的密钥,永远不要相信环境变量能在前端构建中隐藏任何东西。

今天就启用 GitHub 的推送保护。这是确保这个问题不再发生的最简单方法。

常见问题

通过你的 API 提供商的控制面板立即撤销或禁用已泄露的密钥。不要等到先清理 Git 历史记录。密钥在推送到公共仓库的那一刻就已经被泄露了,自动化机器人可以在几秒钟内捕获它。撤销后,生成新密钥并更新你的应用程序。

不可以。Git 保留所有历史记录,因此密钥仍然可以在先前的提交、分支副本、现有克隆以及修复前创建的任何副本中访问。删除或修改提交只会将其从当前分支顶端删除。无论你之后执行什么历史清理,都必须撤销密钥。

不安全。这些带前缀的环境变量会直接打包到你的前端 JavaScript 中,任何打开浏览器开发者工具的人都能看到。它们用于公共配置值,而不是密钥。任何授予特权访问的密钥都必须存储在服务器端,并通过 API 路由或后端代理访问。

启用 GitHub 推送保护,在包含检测到的密钥的提交到达仓库之前将其拦截。使用带有 gitleaks 或 detect-secrets 等工具的预提交钩子在本地扫描更改。在 CI 流水线中添加密钥检测作为额外的安全网。这些层级协同工作,尽早捕获错误。

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay