软件真是个有趣又深奥的东西,它由看似神奇的代码片段组成,这些代码运行在最终的终端上,本身却并非生命体,但拥有自己的生命周期。
软件最初是源代码的形式,仅仅是存放在某个仓库的文本文件,然后通过独特的构建过程,这些源代码会转变为其他形式。例如交付到 web 服务器的压缩 JavaScript 代码块、包含框架代码和业务逻辑的容器镜像,或者针对特定处理器架构编译的原始二进制文件。
这种最终的形态转变,也就是源代码生成的其他形式,通常被称为“软件制品”。在创建之后,制品通常会处于休眠状态,等待被使用。它们可能会被放置在软件包注册表(例如 npm、RubyGems、PyPI 等)或容器注册表(例如 GitHub Packages、Azure Container Registry、AWS ECR 等)中,也可能作为附加到 GitHub 版本发布的二进制文件,或者仅仅以 ZIP 文件的形式存储在某个 Blob 存储服务中。
最终,有人会决定拾取该制品并使用它。他们可能会解压缩包、执行代码、启动容器、安装驱动程序、更新固件 - 无论采用何种方式,构建完成的软件都将开始运行。
这标志着生产生命周期的顶峰,该周期可能需要大量人力投入、巨额资金,并且鉴于现代世界依赖软件运行,其重要性不言而喻。
然而,在许多情况下,我们并不能完全保证所运行的制品就是我们构建的制品。制品经历的旅程细节要么丢失,要么模糊不清,很难将制品与其来源的源代码和构建指令联系起来。
这种缺乏对制品生命周期的可见性是当今许多最严峻的安全挑战的根源。在整个软件开发生命周期 (SDLC) 中,有机会保护代码转换为制品的流程 - 如此一来,可以消除威胁行为者破坏最终软件并造成严重后果的风险。一些网络安全挑战似乎难以成功应对,但这种情况并非如此。让我们深入了解一些背景知识。
哈希值和签名
假设你的目录中有一个文件,并且你想要确保它明天与今天完全相同。你该怎么做?一个好的方法是通过安全的哈希算法生成文件的哈希值。
以下是如何使用 OpenSSL 和 SHA-256 算法完成此操作:
openssl dgst -sha256 ~/important-file.txt |
现在,你拥有了一个哈希值(也称为散列值),它是一个由字母和数字组成的 64 字符字符串,代表该文件的唯一指纹。只要更改该文件中的任何内容,然后再次运行哈希函数,你就会得到不同的字符串。你可以将哈希值写在某个地方,然后第二天回来尝试相同的过程。如果你两次没有得到相同的哈希值字符串,则文件中的某些内容已发生更改。
到目前为止,我们可以确定某个文件是否被篡改。如果我们想要对制品进行声明怎么办?如果我们想说“我今天看到了这个制品,我(系统或人)保证这个东西就是我看到的东西”,该怎么办?此时,你需要的是软件制品签名;你需要将哈希值字符串通过加密算法进行处理,以生成另一个字符串,代表使用唯一密钥“签名”该指纹的过程。
如果你随后希望其他人能够确认你的签名,则需要使用非对称加密:使用你的私钥签名哈希值,并提供相应的公钥,以便任何获取你文件的人都可以进行验证。
你可能已经知道,非对称加密是互联网上几乎所有信任的基础。它可以帮助你安全地与银行互动,也可以帮助 GitHub 安全地交付你的存储库内容。我们使用非对称加密来支持诸如 TLS 和 SSH 等技术,以创建可信赖的通信通道,但我们也使用它通过签名来创建信任软件的基础。
Windows、macOS、iOS、Android 等操作系统都具有用于确保可执行软件制品的可信来源的机制,方法是强制要求存在签名。这些系统是现代软件世界中极其重要的组件,构建它们非常困难。
不仅仅是签名 - 还要证明
当我们思考如何展示关于软件制品的更多可信赖信息时,签名是一个好的开端。它表示“某个可信赖的系统确实看到了这个东西”。但是,如果你真的想在整个软件开发生命周期 (SDLC) 的安全性方面取得重大进步,那么你就需要超越简单的签名,而是要考虑证明。
证明是一种事实断言,是对制品或制品所做的声明,并由可被认证的实体创建。之所以可以进行认证,是因为声明已签名,并且用于签名的密钥是可信的。
最重要和最基础的证明类型之一是断言有关制品来源和创建的事实 - 它来自的源代码和将源代码转换为制品的构建指令,我们称之为来源证明。
我们选择的来源证明规范来自 SLSA 项目。SLSA 是考虑软件供应链安全性的绝佳方式,因为它为软件的生产者和消费者提供了一个通用的框架,用于推理安全保证和边界,而这与特定的系统和技术栈无关。
SLSA 基于 in-toto 项目的工作,提供了一种用于生成软件制品来源证明的标准化架构。in-toto 是一个 CNCF 毕业项目,其存在目的之一是提供一系列有关供应链和构建过程的相关信息的标准化元数据架构。
构建这样的东西需要什么?
GitHub 作为托管大量代码和构建管道的全球最大软件开发平台,对此进行了大量的思考。构建认证服务需要许多活动部件。
这样做意味着有一种方法可以:
- 颁发证书(本质上是绑定到某个经过身份验证的身份的公钥)。
- 确保这些证书不会被滥用。
- 在众所周知的上下文中启用工件的安全签名。
- 以最终用户可以信任的方式验证这些签名。
这意味着设置证书颁发机构 (CA) 并拥有某种客户端应用程序,你可以使用它来验证与该颁发机构颁发的证书相关联的签名。
为了防止证书被滥用,你需要 (1) 维护证书吊销列表或 (2) 确保签名证书是短期的,这意味着需要某种时间戳机构的反签名(可以提供权威印章,表明证书仅在其有效期内用于生成签名)。
这就是 Sigstore 的作用所在,它是一个开源项目,提供 X.509 CA 和基于 RFC 3161 的时间戳机构。它还允许你使用 OIDC 令牌进行身份验证,许多 CI 系统已经生成了令牌并将其与其工作负载相关联。
Sigstore 对软件签名的作用与 Let’s Encrypt 对 TLS 证书的作用相同:使其简单、透明且易于采用。
GitHub 通过在技术指导委员会中的席位帮助监督 Sigstore 项目的治理,是服务器应用程序和多个客户端库的维护者,并且(与来自 Chainguard、Google、RedHat 和 Stacklok 的人员一起)组成了 Sigstore 公共物品实例的运营团队,该团队的存在是为了支持 OSS 项目的公共证明。
Sigstore 需要符合更新框架 (TUF) 规定的标准的安全信任根。这允许客户端跟上 CA 底层密钥的轮换,而无需更新其代码。TUF 的存在是为了缓解在现场更新代码时可能出现的大量攻击媒介。许多项目都使用它来更新长期运行的遥测代理、提供安全的固件更新等。
有了 Sigstore,就可以创建防篡改的纸质跟踪,将工件与 CI 联系起来。这一点非常重要,因为以无法伪造的方式签署软件和捕获出处细节,意味着软件消费者有办法执行他们自己的规则,以确定他们正在执行的代码的来源。
原文:https://github.blog/2024-04-30-where-does-your-software-really-come-from/
转载本站文章请注明作者和出处,请勿用于任何商业用途。欢迎关注公众号「DevOps攻城狮」