Go 1.21 工具链现已可复现,帮助防范供应链攻击

Go 1.21工具链成为首个完全可重现的Go工具链

Google工程师Russ Cox解释,Go 1.21工具链是首个完全可重现的Go工具链,这减少了恶意行为者篡改输出二进制文件以实施供应链攻击的风险。

可重现构建的重要性

可重现构建意味着每次从相同的源代码和输入开始,都会生成相同的输出。这使得任何人都可以通过重新构建并比较输出与发布的二进制文件来验证发布的二进制文件是否没有恶意更改。

这种方法证明了二进制文件没有后门或其他不在源代码中的更改,而无需对其进行反汇编或检查。由于任何人都可以验证二进制文件,独立团体可以轻松检测并报告供应链攻击。

不可重现性的风险

不可重现性意味着恶意行为者可以在下游计算机中修改生成的二进制文件,这通常比修改上游源代码更容易,而这些更改不会被其原始作者或用户检测到。开源社区中对可重现性的重视也体现在新的“可重现构建”倡议中。

这对于开发隐私或安全软件的开发者尤为重要,因为攻击这些软件通常会危及政治敏感目标,如异议人士、记者和举报人,以及任何希望在压制政权下安全通信的人。

Go 1.21的可重现性改进

以前的Go工具链虽然支持可重现构建,但需要大量努力。Go 1.21通过消除所有相关输入(即影响构建过程输出的输入,除了源代码本身),使这一过程变得无缝。

常见的影响可重现性的相关输入包括源代码或依赖项的特定版本、操作系统或CPU架构、编译器版本、运行构建的用户/组等。Cox指出,虽然记录任何相关输入确实可以提供一种使构建可重现的方法,但使其易于重现(即完全可重现)的唯一方法是消除除源代码本身之外的任何相关输入。

迈向完全可重现的历程

Go工具链的可重现性之路始于Go 1.10,当时做出了一些关键决策,包括减少在迭代映射或执行goroutine时的随机性,并将编译器使用的库复制到源代码树中,如sortcompress/zlib,以避免更新构建系统上的这些库可能产生不同的二进制文件。

Go 1.20和1.21添加了实现完全可重现性的剩余构建块。这些包括重写net包以避免依赖构建主机的C工具链,改进Go链接器生成的二进制文件的便携性,使用模块路径而不是源代码目录路径作为运行和调试元数据中的所有内部路径,使浮点代码生成在所有平台上保持一致等。

验证可重现性

Cox表示,通过这些更改,Go工具链完全可重现。事实上,谷歌在两个非常不同的系统上构建所有Go发行版,一个受信任的Linux/x86-64主机和一个Windows/x86-64主机,并验证它们是否生成完全相同的二进制文件,否则会废弃该构建。

为了其他开发者进行同样的验证,谷歌发布了一个验证器,它将重建当前的Go版本,并检查是否与官方存档匹配。

Cox的文章包含了更多技术细节,感兴趣的读者不应错过。

阅读 22
0 条评论