如今的组织非常重视软件和应用的开发和上市速度。但是,当现有的安全做法无法跟上这种速度时,就会导致开发延迟、带来风险的妥协和威胁漏洞。
在此报告中,您将了解如何通过以下方法解决软件供应链安全问题:
- 采用行业标准和框架
- 借助在零信任架构中使用最小权限原则的托管式服务来实现这些标准
了解如何在一个安全的基础上快速完成包括代码编写、构建、打包、部署和运行的软件开发流程。
对于构建软件和应用以满足客户需求的所有组织而言,开发和上市速度是重中之重。 这些战略重点是容器平台爆发式增长的驱动力。过去一年,在享受了容器技术在上市速度、可用性、安全性、可伸缩性以及费用方面的优势后,许多组织也开始考虑无服务器方法。
虽然软件解决方案缩短了提供新功能甚至是新产品所需要的时间,但许多现有的安全做法无法跟上这种速度,从而导致了三个问题:
过去几年中,出现过一系列被归类为“软件供应链”攻击的安全事故。
Log4Shell 是 2021 年 12 月在 Apache Log4j 软件中发现的危险漏洞。该漏洞的 CVSS 分数是最高的 10 分,由于基于 Java 的日志记录框架 Log4j 非常流行,因此这个漏洞破坏力巨大。 它的严重性来源于两个方面:首先,它很容易被利用,并且允许执行完整的远程代码;其次,它通常深藏在依赖关系树中许多层的下面,因此很容易被忽略。
IT 管理软件公司 Solarwinds 遭遇了国家级别攻击者的攻击,攻击者将恶意代码注入该公司正在使用的开源软件的官方版本中。此恶意更新被推送给 18,000 名客户,包括美国财政部和商务部。
另一家 IT 管理软件提供商 Kaseya 遭到了零日漏洞的攻击,攻击者利用该漏洞入侵了 Kaseya VSA 服务器并通过恶意脚本发送勒索软件,导致受影响系统上的所有文件都被加密。
由于迫切需要应对此类突发事件,白宫在 2021 年 5 月发布了一项行政命令,要求与联邦政府有业务往来的组织遵循特定的软件安全标准。
从许多方面来看,“软件供应链”这一术语都是非常恰当的:创建软件供应链的过程与制造汽车的过程非常相似。
汽车制造商获取各种现成的零部件,生产自己的专有组件,然后通过高度自动化的流程将它们组装在一起。 为了保证运营安全,制造商会确保每个第三方零部件都来自可信的来源。 第一方组件则经过广泛测试,确保不存在安全问题。 最后,通过可信的流程进行组装,最终生产出成品汽车。
软件供应链在很多方面是相似的。软件制造商获取第三方组件(通常是执行特定功能的开源组件),并开发自己的软件(其核心知识产权)。 然后通过构建流程运行代码,构建流程会将这些组件组合成可部署的工件并部署到生产环境中。
只要有一个环节不安全,软件供应链就可能会被破坏。
与去年备受关注的攻击一样,整个流程中的每个步骤都可能产生容易被攻击者利用的漏洞。
例如,常规 npm 软件包有 12 个直接依赖项和大约 300 个间接依赖项。 此外,我们了解到在所有已发布的 npm 软件包中,有近 40% 依赖于存在已知漏洞的代码。
这些漏洞并不一定会真正损害代码安全;例如,代码库中包含漏洞的那个部分可能从未被用到, 但这些漏洞仍然需要检查。
这个问题十分严重。只要有一个漏洞未得到修补,恶意攻击者就有可能获得入侵软件供应链的机会。
威胁 | 已知的示例 | |
A | 将有缺陷的代码提交到源代码库 | Linux 伪装者提交:研究人员试图通过邮件列表上的补丁故意向 Linux 内核引入漏洞。 |
B | 入侵源代码控制平台 | PHP:攻击者入侵了 PHP 自托管的 git 服务器,并注入了两项恶意提交。 |
C | 按照官方流程进行构建,但使用的代码与源代码控制机制不匹配 | Webmin:攻击者修改了构建基础设施,以使用与源代码控制不匹配的源文件。 |
12 | 入侵构建平台 | SolarWinds:攻击者在每次构建中都入侵构建平台并安装植入程序来注入恶意行为。 |
东 | 使用恶意依赖项(即递归地从 A 到 H) | event-stream:攻击者添加了一个无害的依赖项,然后更新该依赖项以添加恶意行为。更新与提交到 GitHub 的代码不匹配(即攻击 F)。 |
2 | 上传不是通过 CI/CD 系统构建的工件 | Codecov:攻击者使用泄露的凭据将恶意工件上传到 Google Cloud Storage 存储桶,而用户直接从该处下载。 |
G | 入侵软件包代码库 | 对软件包镜像的攻击:研究人员运行了几个热门软件包仓库的镜像,这些镜像可能被用于提供恶意软件包。 |
H | 诱骗消费者使用恶意软件包 | Browserify 误植域名:攻击者上传了与原始软件包名称相似的恶意软件包。 |
威胁
已知的示例
东
使用恶意依赖项(即递归地从 A 到 H)
event-stream:攻击者添加了一个无害的依赖项,然后更新该依赖项以添加恶意行为。更新与提交到 GitHub 的代码不匹配(即攻击 F)。
数十年来,Google 一直致力于开发全球级应用。 随着时间的推移,我们逐步对许多内部项目进行了开源,以帮助开发者提高开发速度。 与此同时,我们开发了各种内部流程来帮助保障软件体验的安全。
以下是我们为加强软件供应链安全性做出的一些努力。
我们认为,如需避免软件供应链安全问题,以下两项是必需的:
下面我们将逐一讨论这两个要求:
当前状态的 SLSA 是一套基于行业共识确立的安全准则,可以以递增的方式采用。 在最终成型后,SLSA 与一系列最佳实践的区别在于其强制性:它将支持自动创建可审核的元数据,这些元数据可以馈入政策引擎,用于向特定的软件包或构建平台授予“SLSA 认证”。
SLSA 是一个递增式的框架并且切实可行,可在每一个步骤中提供安全优势。 如果某个工件满足最高级别的要求,消费者就可以确信它未遭到篡改并且可以安全地追溯来源。这一点是现今的大部分软件很难甚至无法做到的。
SLSA 有四个级别,其中 SLSA 4 代表理想的最终状态。较低的级别代表具有相应的递增完整性保证的递增里程碑。 其要求目前定义如下:
SLSA 1 要求构建流程必须完全脚本化/自动化并能够生成出处。出处是关于工件构建方式的元数据,包括构建流程、顶级来源和依赖项。了解出处后,软件消费者可以做出基于风险的安全决策。 虽然 SLSA 1 级别的出处无法防范篡改,但它提供了基本的代码来源识别能力,并且可用于漏洞管理。
SLSA 2 要求使用版本控制和可生成经身份验证的出处的托管构建服务。这些额外要求可让消费者对软件的来源更有信心。 在此级别,出处可以防范篡改,使得构建服务可以被信任。 从 SLSA 2 可以很容易地升级到 SLSA 3。
SLSA 3 进一步要求源平台和构建平台满足特定标准,以分别保证来源的可审核性和出处的完整性。SLSA 3 可以防范特定类别的威胁(例如跨构建污染),从而提供比之前两个级别更强的防篡改能力。
SLSA 4 是目前的最高级别,要求对所有更改进行双人审核,并要求构建流程封闭且可重现。双人审核是发现错误和防止不良行为的行业最佳实践。封闭的构建流程可保证出处的依赖项列表是完整的。 可重现的构建流程并非强制要求,它可以提供很多可审核性和可靠性方面的好处。 总体而言,SLSA 4 可以让使用者确信软件未被篡改。如需详细了解这些建议的级别,请查看 GitHub 代码库,包括相应的来源和构建/出处要求。
软件供应链可分为五个不同的阶段:编码、构建、打包、部署和运行。我们将从我们的安全保障方法的角度来说明每个阶段。
Google Cloud 提供贯穿代码编写、构建、部署和运行的全代管式工具,这些工具默认实施上述标准和最佳实践。
要保护软件供应链安全,需要建立、验证和维护一个信任链,这个信任链可建立代码的出处,并确保在生产环境中运行的应用符合您的预期。 在 Google,我们通过在整个软件开发和部署过程中生成和检查的证明来满足这一要求,通过代码审核、经过验证的代码出处以及政策强制执行来建立环境安全性。在这些流程的共同作用下,我们能够最大限度地降低软件供应链风险,同时提高开发者的工作效率。
在底层,我们有常见的安全基础架构服务,例如身份和访问权限管理及审核日志记录服务。 然后,我们使用在整个软件生命周期中定义、检查和强制执行证明的方法来保护软件供应链安全。
下面,我们将详细说明如何通过 Google Cloud 中的政策和出处在开发流程中实现环境安全性。
从开发者开始设计应用和编写代码时,软件供应链的保护就开始了。 这包括第一方软件和开源组件,它们各自有不同的挑战。
开源软件和依赖项
开源使开发者能更快地构建应用,使组织变得更加灵活和高效。 但开源软件并不是绝对完美的,而我们的行业依赖于开源软件,但我们往往对开源软件的依赖项以及随之而来的各种风险知之甚少。 对于大多数企业来说,风险主要源自漏洞或许可。
您依赖的开源软件、软件包、基础映像和其他工件构成了“信任链”的基础。
例如,假设您的组织正在构建软件“a”。此图显示了信任链,也就是项目中的隐式依赖项的数量。 在图中,“b”到“h”是直接依赖项,“i”到“m”是间接依赖项。
现在,假设依赖关系树靠下的层中有一个漏洞。 这个问题很快就会体现在许多组件上。 此外,依赖项的变化很频繁:平均每天有 4 万个 npm 软件包的依赖项会发生变化。
Open Source Insights 是由 Google Cloud 构建的工具,它提供传递依赖关系图,因此您可以在依赖关系树中查看您的依赖项以及它们的依赖项。我们会持续更新 Open Source Insights,并在一个平台上以多种语言发布安全公告、许可信息和其他安全数据。 与开源计分卡(可为开源项目提供风险评分)一起使用时,Open Source Insights 可帮助开发者从数以百万计的开源软件包中选择最适合的软件包。
要解决此问题,关键是要重视依赖项即代码。 随着这些依赖项逐渐接近供应链的末端,检查会变得更困难。 为保障依赖项的安全,我们建议从供应入手:
我们将在下文详细介绍构建和部署流程,但验证构建的出处、利用安全的构建环境以及确保映像经过签名且随后在部署时经过验证也很重要。
开发者还可以采用多种安全的编码做法:
保护软件供应链安全的下一步涉及大规模打造安全的构建环境。 实质上,从代码库导入某种语言的源代码以及按照配置文件中列出的规范执行构建起,构建流程就开始了。
Google 等云服务提供商会提供最新的代管式构建环境,供您以所需的任何规模构建映像。
在整个构建流程中,您需要考虑以下事项:
如需开发安全的构建环境,您应该从密文着手。它们十分重要,并且相对比较容易保护。首先确保密文绝对不采用明文形式,并且尽可能不要在构建过程中使用。 您应确保密文已加密,并且构建已参数化以根据需要引用要使用的外部密文。 这也简化了密文的定期轮替过程并降低了泄露造成的影响。
下一步是为构建设置权限。 构建流程涉及各种用户和服务账号。例如,一些用户可能需要能够管理密文,其他用户可能需要通过添加或修改步骤来管理构建流程,而另一些用户可能只需要查看日志。
在此过程中,请务必遵循以下最佳实践:
接下来,随着此过程的扩大,尽可能在构建周围建立边界,然后通过配置即代码和参数化自动扩大规模。 这样,您就可以有效地审核对构建流程所做的任何更改。 此外,通过对敏感构建和部署设定批准门槛、发送对基础架构更改的拉取请求,以及定期对审核日志进行人工审核,来确保满足合规性需求。
最后,确保网络符合您的需求。在大多数情况下,最好在受防火墙保护的专用网络中托管您自己的源代码。 在 Google Cloud 中,您可以使用 Cloud Build 专用池、专用网络边界内的锁定无服务器构建环境等功能,还可以使用 VPC Service Controls 等功能来防止知识产权泄露。
Binary Authorization
虽然 IAM 是必备安全措施和逻辑起点,但它并不能保证万无一失。 凭据泄露可能导致严重的安全风险,因此,为了减少对 IAM 的依赖,您可以使用基于证明的系统,这种系统不易出错。 Google 使用名为 Binary Authorization 的系统,它仅允许部署可信的工作负载。
在整个流程中,Binary Authorization 服务会通过证明和政策检查建立、验证和维护信任链。 从本质上讲,在代码和其他工件转变为生产环境软件的过程中,Binary Authorization 会生成加密签名(即证明),然后在部署前根据政策检查这些证明。
使用 Google Cloud Build 时,系统会捕获一组证明并将其添加到整个信任链中。 例如,系统会针对运行的任务、使用的构建工具和流程等生成证明。 值得注意的是,Cloud Build 通过捕获构建配置的来源(这些数据可用于验证构建是否是通过脚本执行的)帮助您满足 SLSA 级别 1 要求。 脚本化构建比手动构建更安全,SLSA 级别 1 要求使用这种构建方式。 此外,您可以使用容器映像摘要查询构建的出处和其他证明,这会为任何映像创建唯一签名,这也是 SLSA 级别 1 的要求。
构建完成后,您将获得一个几乎可以立即在生产环境中使用的容器映像。 请务必将映像存储在安全的位置,以防止现有映像被篡改或者上传未经授权的映像。 您的软件包管理器可能需要同时包含第一方构建和开源构建的映像,以及应用使用的语言包。
Google Cloud 的 Artifact Registry可为您提供这样的制品库。Artifact Registry 使组织可以集中管理容器映像和语言包(如 Maven 和 npm)。 该产品可与 Google Cloud 的工具和运行时环境完全集成,并支持原生工件协议。因此,在设置自动化流水线时,您可以轻松地与 CI/CD 工具集成。
与构建步骤类似,请务必遵循最小权限原则,谨慎地授予对 Artifact Registry 的访问权限。 除了限制未经授权的访问之外,软件包代码库还可以提供更多价值。 例如,Artifact Registry 提供漏洞扫描功能,可扫描映像以确保映像是安全的,可放心部署。此服务会根据不断刷新和更新的漏洞数据库扫描映像,以评估是否存在新威胁并在发现漏洞时发出提醒。
此步骤会生成额外的元数据,包括关于工件的漏洞结果是否满足特定安全阈值的证明。 然后,这些信息会存储在我们的分析服务中,该服务会构建并整理工件的元数据,以供 Binary Authorization 访问。 此方法可用于自动防止将有风险的映像部署到 Google Kubernetes Engine (GKE)。
软件安全供应链的最后两个阶段是部署和运行。 虽然这两个步骤是分开的,但将它们放在一起考虑有助于确保只有获得授权的构建才能进入生产环境。
在 Google,我们制定了一些最佳实践用于确定应该对哪些类型的构建进行授权。 首先,应确保供应链的完整性,使其仅生成您可以信任的工件。 其次,在软件交付生命周期中纳入漏洞管理。 最后,我们将这两点结合起来,强制执行基于完整性和漏洞扫描政策的工作流。
至此,您已经完成了编码、构建和打包阶段,可以使用 Binary Authorization 验证沿着供应链获取的证明的真实性。在实施模式下,只有当证明符合组织的政策时才会部署映像;在审核模式下,系统会记录违反政策的行为并触发提醒。 此外,您还可以使用 Binary Authorization 来限制版本运行,除非这些版本是使用已获批准的 Cloud Build 流程构建的。 Binary Authorization 可确保仅部署经过适当审核和授权的代码。
将映像部署到可信的运行时环境至关重要。我们的托管式 Kubernetes 平台 GKE 对容器采用安全至上的方法。
GKE 负责处理您需要注意的许多集群安全问题。 自动升级集群的功能可使用发布渠道自动修补您的 Kubernetes 并使其保持最新。 安全启动、安全强化型节点和完整性检查可确保节点的内核和集群组件没有被修改并且运行着预期的内容,并可确保恶意节点无法加入集群。最后,机密计算允许您运行包含内存加密的节点的集群,这样,数据即使在被处理时也能保持机密性。再加上静态数据加密和传输中数据加密功能,GKE 提供的环境极为安全、私密和机密,适合运行容器化工作负载。
除此之外,GKE 还通过负载均衡器证书管理、工作负载身份和高级网络功能为应用提供更高的安全性,并通过一种强大的方法配置和保护传入集群的入站流量。GKE 还提供沙盒环境来运行不受信任的应用,同时有效保护其余工作负载。
借助 GKE Autopilot 可自动实现 GKE 的安全最佳实践和功能,进一步缩小受攻击面并尽可能减少可能引起安全问题的错误配置。
当然,验证并不仅限于部署。Binary Authorization 还支持持续验证,即使在部署后也能够持续与定义的政策保持一致。如果正在运行的应用不符合现有或新添加的政策,系统会创建并记录提醒,这可以使您确信生产环境中运行的应用完全符合预期。
漏洞管理
除了确保完整性之外,供应链安全的另一个要素是确保快速发现并修补所有漏洞。 如今的攻击者已经可以主动将漏洞插入上游项目中, 因此应在软件交付生命周期的所有阶段纳入漏洞管理和缺陷检测。
代码可供部署后,可利用 CI/CD 流水线和许多可用工具来对源代码和生成的工件进行全面扫描。这些工具包括静态分析器、模糊测试工具和各种类型的漏洞扫描程序。
将工作负载部署到生产环境后,当其在生产环境中运行并为用户提供服务时,需要监控新出现的威胁并制定计划立即采取补救措施。
总结
简而言之,确保软件供应链安全的关键在于采用 SLSA 等最佳实践,并使用可帮助实施这些最佳实践的可信代管式服务。
您应确保遵循以下做法:
我们在 Google 产品组合交付生命周期的每一步中都融入了相应的最佳实践,让您可以在值得信赖的基础架构上构建应用。
准备好开始保护您的软件供应链了吗?需要了解的是,从何处入手在很大程度上可以任意选择,没有哪一项操作可以保护您的整个供应链,就供应链整体安全而言,也没有哪一项操作比其他操作更重要。 尽管如此,我们还是提供以下四条建议供您开始着手此工作。
1. 修补您的软件
如果您已将包含已知漏洞的代码部署到生产环境中,您就给攻击者帮了大忙。 从这时起,软件供应链的安全性变得无关紧要,因为攻击者已经有了可利用的漏洞。因此,进行修补非常重要。
2. 控制您的环境中运行的组件
完成修补后,您需要能够控制软件供应链本身。 首先,您需要能够确保您运行的组件均来自您的构建工具或可信代码库。 这种程度的控制有助于防止故意攻击和意外错误(例如开发者部署了不安全的工件却毫不知情)。 这可以为添加点击测试和 Binary Authorization 等工具奠定坚实的基础。
3. 确保第三方供应商软件包是安全的
一个日益严重的供应链安全问题是,供应商的软件频繁遭到入侵,为攻击者提供了通道来向供应商的目标客户部署植入勒索软件或进行非法访问。 在您的环境中运行的第三方供应商软件包(例如系统管理产品、网络管理产品或安全产品)通常具有较高的权限。我们建议您除了样板安全声明以外,向供应商了解他们还实施了其他哪些安全措施,以便更放心地使用他们的软件包。 您可以询问他们符合的 SLSA 级别,或者了解他们是否在最新发布的行政命令的要求范围之内。
4. 创建源代码的非公开副本
如果您使用开源软件,请不要使用直接从互联网上下载的版本开始构建。 您应该维护一个随时进行修补的非公开副本,这样您就可以为每次构建提供一个明确的起始位置,并且可以百分百确信源代码的来源。
DevOps 最佳实践
保护软件供应链安全