我们以「在你的环境中如何防御」的视角来解读真实发生过的公开事故,而不是把新闻重播一遍。本文是 基于公开记录(官方事后分析、CISA、安全企业的分析)的讲解。出处在文末注明。
- 对象
- Codecov(代码覆盖率测量工具)及其使用企业的 CI
- 公布
- 2021 年 4 月 15 日(篡改始于 1 月 31 日/发觉于 4 月 1 日)
- 手法分类
- 供应链攻击(对被信任的分发物进行上游篡改)+窃取 CI 机密信息
- 影响规模
- Codecov 的大量客户(最多约 29,000)。HashiCorp、Twilio、Rapid7 等发生二次受害
- 根本原因
- CI 未校验取得物就执行 + 分发源密钥管理不当 + CI 机密过度暴露
- 主要对策
- 取得物的完整性校验、CI 机密的最小权限、轮换、egress 监控
发生了什么(通俗版)
很多开发团队会在测试自动执行环境(CI)里,用 curl … | bash 这样的方式把外部工具取下来直接执行。Codecov 的 Bash Uploader 就是这样一个脚本。
攻击者利用 Codecov 一侧分发机制的缺陷,改写了被分发的脚本本体,让它在 CI 中执行时,把该环境里的环境变量(机密信息)发送到外部的服务器。从使用方看来,不过是像往常一样调用了被信任的工具而已。由于自己的代码一行都没变,几乎找不到察觉异常的线索。
约两个月后,某家使用企业把脚本的 校验和(SHA256)与官方的值进行了比对,发现了不一致。篡改就是这样被发现的。可能外泄的信息里包含云的密钥、部署密钥、API 密钥、令牌等,并由此连锁引发了对 HashiCorp、Twilio 等其他公司的二次受害。
自己的代码没有变化,所以很难察觉
供应链攻击瞄准的不是你写的代码,而是你信任并引入之物。所以无论是代码审查还是日志都很难察觉。人们往往不去校验自己信任的工具,而这正是攻击者利用的弱点。
攻击的各个阶段与拦截方法
重要的是,这是一条四步的连锁,而 每一步都有可以阻断的地方。请不要把它读作攻击步骤,而要读作在哪里本可以拦下。
① 用 curl | bash 执行被信任的工具(未校验内容)
⊘ 阻断点:固定取得物+校验和验证 / vendoring
② 该分发物在分发源(上游)被替换
自己的代码毫发无损,所以无从察觉。
⊘ 阻断点:与已知良好的哈希比对、使用固定版本
③ CI 内的环境变量(机密、密钥、令牌)被发送到外部
⊘ 阻断点:把 CI 机密收紧到最小权限、按步骤限定(不要把全部 env 都传过去)
④ 用偷来的密钥向生产环境、其他服务波及二次受害
⊘ 阻断点:密钥的定期轮换+egress(外向通信)监控
已公布的时间线
2021-01-31
Bash Uploader 的篡改开始(此后断断续续)。2021-03〜
使用企业的 CI 中的机密信息持续被发送到外部(无人察觉)。2021-04-01
某客户发现校验和不一致并上报。2021-04-15
Codecov 正式公布。建议使用企业全面更换机密。2021-04〜
HashiCorp、Twilio、Rapid7 等的二次受害陆续查明。Codecov 后来废弃了 Bash Uploader。
根本原因:不止一个失误
如果以「都怪 Codecov」收场,就会重演。在使用方这一侧,也 缺失了多道防御。
失守的配置(事故时)
- CI 未校验取得物就执行(把
curl | bash全凭信任) - CI 机密过度暴露(所有步骤都能看到全部环境变量)
- 机密的轮换很少(被偷的密钥长期有效)
- 不监控 CI 的外向通信
守住的配置(防止重演)
- 取得物采用固定版本+校验和验证,或自行引入(vendoring)
- CI 机密以最小权限、只在必要的步骤传递
- 机密定期轮换(即便泄露也让寿命很短)
- 监控 CI 的 egress,检测向陌生目的地的发送
即使是信任的工具,也要校验
供应链攻击瞄准依赖库、CI 工具、构建镜像等「信任并引入之物」。XZ Utils 事件也是同一种结构。把信任最小化,并对引入之物的完整性进行机械化校验,才是正解。
在你的环境中如何防止重演
下面是无论规模大小都有效、按优先级排序的对策。把 CI 信任并执行的东西列出来一次,就能看清哪里与你有关。
校验取得物的完整性(不要把 curl|bash 全凭信任)
若要在 CI 中引入外部脚本或二进制,请把固定版本(版本/提交固定)+校验和(SHA256)比对作为必须项。可能的话就引入到自己的仓库(vendoring)。这次的检测,靠的也正是这种比对。
把 CI 的机密最小权限化、按作用域限定
不要把全部环境变量传给所有步骤。只把需要的机密传给需要的作业、步骤。使用短命令牌(OIDC 等),减少长期密钥的常驻。
定期轮换机密
即便被偷,寿命短则受害有限。把定期轮换做成机制,一旦有供应链事件被报道就立即轮换。
监控 CI 的外向通信(egress)
让 CI 向陌生目的地的发送能够被检测到。即便在引入时没能发现被篡改的工具,也要留下一层能在外泄环节察觉的防线。
本站的立场:最小化信任,并加以校验
本站自身也是以用机器校验依赖与构建引入物为前提来设计的。Codecov 事件与 XZ Utils 揭示的是同一件事:「在信任」很容易变成「没在校验」,而供应链攻击利用的正是这一点。减少信任,对引入之物的完整性进行机械化确认。
出处(公开记录)
本文的事实基于以下公开信息。不涉及攻击的复现步骤与篡改代码,只聚焦于防御的教训。
- Codecov 官方「Post-Mortem / Root Cause Analysis (April 2021)」— about.codecov.io
- Codecov 官方「Bash Uploader Security Update」— about.codecov.io
- CISA「Codecov Releases New Detections for Supply Chain Compromise」(2021) — cisa.gov
- Rapid7「Analysis of the Codecov Supply Chain Compromise」(2021) — rapid7.com