LWN: 秘钥扫描!
关注了就能看到更多这么棒的文章哦~
Scanning for secrets
By Jake Edge
April 7, 2021
DeepL assisted translation
https://lwn.net/Articles/851670/
即使是开源项目,有时也有需要维护一些秘密信息。比如像签名密钥这类数据,应该被安全地储存,不可以跟项目代码放在一起,还有用于访问各种网络服务的凭证和令牌(credentials and tokens),例如访问云托管(cloud-hosting)服务或 Python Package Index(PyPI)的凭证。这些凭证有时是运行这部分代码的实例所必须的,还有一些凭证会希望存储在代码 "附近",但这些凭证都不可以分发给本项目的工作人员之外。然而,它们有时会被错误地添加到公开的代码库(public repository)中,这样一来肯定会被攻击者注意到。像 GitHub 和 GitLab 这样的大型存储库托管服务商,可以有效地扫描出这些被提交到项目存储库中的秘密信息,而且他们也确实在这样做。
源代码仓库,天然容易吸引开发者把这类信息存储进来,因为项目开发者需要这些信息就在手边,显然,Git 仓库就符合这个需求。当然,这样做会有一些问题。这些秘密数据只是为了此项目本身使用的,所以公开它们可能会违反网络服务(如 Twitter 或谷歌地图)的服务条款。更糟糕的是,可能被利用来使用项目的云基础设施来生产加密货币(挖矿),或者导致任何人都可以发布代码,看起来就好像是官方发布一样。另外,一旦秘密数据被提交并推送到公开代码仓库,那么就会成为代码库固有历史的一部分。很难撤销这个操作,而且实际上无法把牙膏塞回牙膏皮里,因为任何在版本库被更新之前 clone 或 pull 过的人仍然拥有这些秘密信息。
一旦某个项目意识到它无意中在其源代码仓库公开了一个秘钥,那么就需要让颁发这个秘钥的机构撤销此证书,重新颁发一个新的证书。但是,在这个错误被注意到之前,可能会有一个漫长的时间窗口。哪怕它很快就被注意到,也可能需要一些时间来让颁发者撤销该秘钥。如果可能的话,这些最好都避免发生。
多年来,由于证书被提交到 Git 仓库并发布在 GitHub 上,已经导致了各种各样的问题。五年前的一篇文章中谈到了 Uber 的数据泄露事件,就是因为错误地把亚马逊网络服务(AWS)凭证提交到了 GitHu;后来的一次更大的泄露事件也是使用了被盗的凭证信息来访问到了一个存储了其他许多 AWS 凭证的 GitHub 私有仓库。那篇文章还介绍了 Detectify 的一篇博文,其中描述了该公司如何通过扫描 GitHub 仓库来发现一些 Slack token。当然,这类问题其实更早就发生过了。2019 年的一篇论文显示,这个问题也并没有真正缓解,其实我们也并不感到意外。
自 2015 年以来,GitHub 一直在扫描各种秘密信息。它一开始是查找自己的 OAuth token。2018 年的时候,该公司扩大了扫描范围,也会寻找其他类型的 token 和 credential:
自从 4 月以来,我们与云服务提供商在 private beta 版本中合作,来扫描公共存储库和公共 Gists 的所有变动,来搜寻凭证信息(GitHub 不会扫描 private code)。搜索出来的每个可能是凭证信息的数据都会被发送给供应商,其中包括一些基本的 metadata 比如仓库名称、引入该凭证数据的 commit。提供者随后可以验证该凭证,并根据用户或提供者的相关风险来决定是否应该撤销该凭证。无论选择哪种方式,提供商通常都会联系该凭证的所有者,让他们知道发生了什么事情以及已经采取了什么措施。
如今,GitHub 已经有了一个长长的 secret type 列表支持进行扫描,这公开列在其 secret-scanning documentation 中。当它在新的 commit(或新添加的仓库的 history commit)中发现了匹配到的秘钥时,它会自动通过一个 HTTP POST 来联系证书颁发者,颁发者可以检查秘密的有效性并决定采取什么行动。这些行动可能包括撤销、通知秘密的所有者,以及可能发布一个新的秘钥给客户来替换这个秘钥。
GitHub 积极邀请服务提供商加入该计划。加入这个计划很简单,只需要在自己的服务器上建立一个 endpoint 来接收 HTTP POST,并向 GitHub 提供一个正则表达式来告知如何匹配到它的秘钥。为了杜绝攻击者滥用这个扫描通知信息的 URL,发送到这个 endpoint 的信息要用 GitHub 的密钥进行签名,会先进行验证,然后再处理这个 "已经泄露的秘钥"。
最近,GitHub 博客上也宣布在秘钥扫描功能中增加了 PyPI token。GitHub 和 PyPI 合作,会帮助保护相关项目免受这类错误的影响:
从今天起,GitHub 将扫描每个公共仓库的提交,以查找暴露的 PyPI API 令牌。我们将把发现的所有令牌转发给 PyPI,后者将自动禁用这些令牌并通知其所有者。这个端到端的过程只需要几秒钟就可以完成。
并不是仅有 GitHub 在做这件事情,GitLab 也在 2019 年的 11.9 版本中加入了秘钥扫描。由于支撑 GitLab 的大部分代码是开源的,"秘钥检测" 功能的代码也可以在 GitLab 的仓库中找到。GitLab 是一个 "open core" 项目,因此其大部分代码都是可以公开获取的,不像 GitHub 是专有软件。至少到目前为止,完全开源的代码库托管服务 SourceHut 似乎尚未实现类似的功能。
GitLab 扫描器是基于 Gitleaks 工具的,会扫描 Git 仓库中存储在 TOML 配置文件中的各种正则表达式。此工具是用 Go 编写的,可以以多种不同方式运行,包括可以对尚未 commit 的本地文件进行扫描。当然,只要定期这样做的话,就有可能使秘钥根本不会被 commit 进去。
GitLab 的扫描文档中列出了它所寻找的秘钥种类,比起 GitHub 的列表要短,但确实已经包括了一些不同类型的秘钥。例如,GitLab 的扫描会查找 SSH 和 PGP 私钥、URL 中的 password 和美国社会安全号码等。gitleaks.toml 文件还显示了一些尚未列入扫描清单的目标,包括 PyPI upload token。
当然,如果这些秘密数据根本就没有进入代码存储库,那就更好了。退而求其次的办法就是在提交者将改动推送到中心版本库之前,就在提交者的系统中发现这些问题。这样做可能还是会更加麻烦一些,但技术上还是可以通过 rebase 操作将这个错误 commit 从代码 history 中完全删除。这两种方法都需要在开发过程中进行某种本地扫描(也许是用 Gitleaks)。不过,在版本库托管服务器上还有一个后备方案(backstop)的话,无疑会有助于让项目负责人更加安心。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~