三 十大 CI/CD 安全风险

在上一篇文章,我们了解了依赖链滥用和基于流水线的访问控制不足这两大安全风险,并给出缓解风险的安全建议 。本篇文章将着重介绍 PPE 风险,并提供缓解相关风险的安全建议与实践 。
Poisoned Pipeline Execution (PPE) 风险指的是攻击者能够访问源代码控制系统,但无法访问构建环境,通过将恶意代码/命令注入构建流水线配置来操纵构建过程,本质上是“中毒的”流水线和运行恶意代码作为构建过程的一部分 。
风险描述PPE 风险通常存在代码仓库中,可控对应的 CI 管道配置文件,通过修改 CI 配置文件达到执行对应命令的目的 。有权操作 CI 配置文件或 CI 流水线任务所依赖的其他文件的攻击者,可以将恶意命令置入这些文件,通过执行这些恶意命令,最终“毒化”执行这些命令的 CI 流水线 。执行未经审查的代码的流水线,比如一些直接由拉取请求或提交到任意存储库分支触发的流水线,由于在设计上包含未经任何审查或批准的代码,更容易受到 PPE 风险的影响 。一旦能够在 CI 流水线中执行恶意代码,攻击者就可以在流水线身份的上下文中进行各种恶意操作 。
PPE 的三种类型直接 PPE(D-PPE)在 D-PPE 场景中,攻击者修改他们有权访问的存储库中的 CI 配置文件,通过直接将更改推送到存储库上未受保护的远程分支,在提交 PR 时随着分叉的更改而变化 。由于 CI 流水线执行是由“push”或“PR”事件触发的,并且流水线执行是由修改后的 CI 配置文件中的命令定义的,一旦构建流水线被攻击,攻击者的恶意命令最终会在构建节点中运行触发 。
间接 PPE(I-PPE)在以下几种情况下,即便攻击者能够访问 SCM 存储库,也无法使用 D-PPE:

  • 流水线配置为从同一存储库中单独的受保护分支中提取 CI 配置文件 。
  • CI 配置文件存储在与源代码不同的存储库中,则用户没有直接编辑它的选项 。
  • CI 构建是在 CI 系统本身中定义的——而不是在存储在源代码中的文件中 。
在这几种情况下,攻击者就会选择向流水线配置文件引用的文件中注入恶意代码来破坏流水线:
  • make:执行“Makefile”文件中定义的命令 。
  • 从流水线配置文件中引用的脚本,与源代码本身存储在同一存储库中(例如,python myscript.py - myscript.py 将被攻击者操纵) 。
  • 代码测试:在构建过程中在应用程序代码上运行的测试框架依赖于专用文件,这些文件与源代码本身存储在同一存储库中 。能够操纵负责测试的代码的攻击者能够在构建中运行恶意命令 。
  • 自动工具:CI 中使用的 Linter 和安全扫描器通常也依赖于存储库中的配置文件 。很多时候这些配置涉及从配置文件中定义的位置加载和运行外部代码 。
【三 十大 CI/CD 安全风险】因此,在 I-PPE 中,不同于将恶意命令直接插入流水线定义文件来破坏流水线,攻击者通过将恶意代码注入到配置文件引用的文件中,一旦触发流水线并运行相关文件中声明的命令,恶意代码最终会在流水线节点上执行 。
公共 PPE(3PE)执行 PPE 攻击需要访问托管流水线配置文件的存储库或其引用的文件 。大多数情况下,只有开发人员拥有此类许可,也就是说攻击者必须要获得开发工程师对存储库的许可和权限才能执行直接或间接 PPE 攻击 。
然而,在一些情况下,互联网上的匿名攻击者可以使用“中毒的” CI 流水线:公共存储库(例如开源项目)通常允许任何用户做出贡献,通过创建拉取请求,建议对代码进行更改 。这些项目通常使用 CI 解决方案自动测试和构建,与私有项目类似 。如果公共存储库的 CI 流水线运行匿名用户建议的未经审查的代码,它很容易受到公共 PPE 攻击,或者简称为 3PE 。如果易受攻击的公共存储库的流水线在与私有存储库相同的 CI 实例上运行,这也会暴露例如私有项目的敏感信息这类的内部资产 。

经验总结扩展阅读