与开源相关的信任问题

信息安全 开源 二进制代码
2021-08-22 00:22:52

最近两次单独的讨论让我看到了一个我没有考虑过的问题——如何确认一个使用的开源二进制文件是基于已发布的源代码。

有一个基于 LeastAuthority.com 的创始人兼首席执行官 Zooko Wilcox-O'Hearn 给 Silent Circle 背后的两位负责人 Phil Zimmermann 和 Jon Callas 的公开信,关于密码学-随机比特的大型讨论线程,该公司运行 Silent Mail这触及了这个话题。此外,Dobbs 博士今天发表的一篇题​​为“ 将所有东西都放在版本控制中”的文章也谈到了它。

这个问题关注的问题是重新编译开源代码并获得与发布的二进制文件相同的结果的能力。换句话说,如果您重新创建相同的二进制文件并从源代码中对其进行哈希处理,则由于工具链的差异和编译器本身的一些随机化,它不太可能完全相同。

Dobbs 博士的文章建议出于可重复性的原因,甚至将工具链置于版本控制之下。Jon Callas 指出,在许多情况下,由于包括许可限制在内的各种原因,可能无法重新分发工具链。除非您自己编译代码,否则您将在假设集中添加一个信任步骤,因为其他人甚至无法以相同的结果重新创建二进制文件。

我现在明白这是一个可以接受的风险。我的问题是,是否有其他讨论或指示与在编译时使源代码字节可重复,从而消除了对甚至开源二进制文件提供者的信任的需要?正如 Jon Callas 的讨论中提到的,Ken Thompson 展示了“你不能相信不是完全由你自己创建的代码”。 关于这个主题的安全含义是什么?

4个回答

没那么简单。

由于可以构建程序的平台数量众多,因此复制原始构建环境可能非常困难。因此,您可能使用不同的编译器,具有不同的设置,使用不同版本的库。环境中的这些细微变化肯定会影响编译的二进制文件。当然,如果作者愿意精确地指定他们的构建环境,或者如果你很幸运(不同的语言会影响这一点),那么就有可能重建完全相同的二进制文件。

对于最近出现此问题的情况,请参阅 TrueCrypt,一个开源的0全盘加密程序。当 TrueCrypt 网站突然被宣布 TrueCrypt 项目意外结束的公告取代时,人们显然对检查代码感兴趣。然而,由于构建环境的不同,构建 TrueCrypt 的不同人经常得到与官方构建大不相同的二进制文件。 一个人显然设法(在重新创建非常接近原始环境的一些艰苦工作之后)从头开始复制 TrueCrypt 构建,编译输出只有轻微的变化。1 当然,除非您愿意尝试同样的事情,否则您无法自己验证这一点。

该页面上有趣的是二进制文件包含编译时间的时间戳。仅此一项就意味着编译和比较哈希永远不会起作用。

0:TrueCrypt 有一个奇怪的许可证,有一些问题;不确定分叉项目是否真的安全。

1:实际上,看起来他们在 TrueCrypt 网站陌生之前就这样做了,但后来也成功地复制了 7.2 版本。

如果您自己编译代码,那么您可能会获得相同的二进制文件。或不。基本上,如果编译器使用确定性优化算法(通常情况下)并且您使用具有相同命令行选项的完全相同的编译器版本(这通常更难确保),那么您的机会很大。

使用正式指定“编译”格式而不是真正优化的编程框架,确定性重新编译更容易。我在这里谈论的是 Java 字节码或 .NET 程序集。使用此类工具时,能够重新编译源代码并获得相同的二进制文件是可能的,尽管很难。使用 C 或 C++,忘记它。

通常的方法是:

  • 自己编译。
  • 让一些受信任的第三方进行编译。该第三方将获得源代码的副本,从他们的机器上执行编译,并(使用密码学或纸质)对源存档和生成的二进制文件进行签名。
  • 让二进制文件的提供者对二进制文件进行签名,并相信逆向工程足够可行,可以在需要时证明犯规行为(同样,在谈论 Java 字节码时,这比已编译的 C 代码更不可信)。
  • 不要使用外部软件;在内部重新实现所有内容(是的,这是一种常用方法,与推荐的方法不同)。
  • 继续相信你的好运(当然不是推荐的方法,但肯定是短期内最便宜的方法)。

请注意,(重新)编译代码还要求进行编译的机器不受恶意控制。这篇非常经典的文章是该主题的必读文章。基本思想是,您的信任仍然必须从某个地方开始(如果仅在硬件本身,其固件被假定为无恶意软件),因此您真正能做的最好的事情就是保持清晰的审计跟踪。这样的痕迹并不能保证不会插入后门,但可以在出现问题时帮助分配责任和责任。

如果您可以重新编译源代码并拥有自己的二进制文件,那么您可能无法获得与分发的二进制文件完全相同的二进制文件;但这有什么关系呢?那时,您拥有自己的二进制文件,它必然与源代码匹配(假设您的编译器本身不是恶意的):您可以放弃二进制包,并使用自己的二进制文件。

换句话说,您可以验证编译输出的情况是您可以自己编译的情况,这使得验证成为一个有争议的问题。

有包分发框架,它们依赖源代码分发和本地编译,而不是二进制包;例如pkgsrc(NetBSD 的本机系统)或MacPorts(MacOS X 机器)。然而,他们这样做并不是为了信任或安全,而是因为二进制包的分发涉及到某个地方的构建系统,而这些系统不是免费的;此外,pkgsrc 的一点是提供对本地编译选项的轻松管理。

著名的 Thompson 文章强调了即使制作自己的汇编也是不够的。走极端,您应该编写自己的代码,还应该编写自己的编译器,并在您自己设计和雕刻的硬件上运行它:除非您从一桶沙子开始(对于,主要组件),否则您无法信任机器半导体)。当然,这是非常不切实际的因此,我们需要次优的东西,而次优的就是范式转变用暴力代替信任

我们所做的是对二进制包进行签名包安装程序在安装之前验证签名,并拒绝不是来自“可信来源”的包。相同的概念适用于Java 小程序,只要它们被签名,就可以被授予额外的权限(实际上,允许对您的计算机做任何他们想做的事情)。请注意,这确实是一个签名,而不仅仅是一个身份验证;仅通过 HTTPS 从“受信任的存储库”下载包是不够的(实际上也没有必要)。这样的下载将给您相当多的保证,即该软件包来自您相信的人,并且在传输过程中没有被修改。但你想要更多:你想要一个证明. 您需要一个签名,因为如果该包被证明是充满恶意软件的时钟,那么您可以使用该签名来证明包提供者是一个共犯,至少“由于疏忽”。签名产生责任,责任产生恐惧害怕被虐待的客户提起诉讼。害怕执法机构的报复。最后,害怕暴力。

的,这是可能的。但这非常困难,因为整个编译过程并不是为了这个目标而设计的。它通常被称为“确定性构建”、“可重复构建”、“幂等构建”,是一个挑战。

比特币、TorDebian正在尝试使用确定性构建,这里描述了技术过程。

诚然,这个过程是不完美的、脆弱的,而且很难做到正确。在考虑跨平台构建时,问题更加复杂。