可重现构建:证明运行的软件就是你检查过的软件
瑞士公布了其投票源代码供任何人检查——研究人员立即发现了一个隐藏的后门,可以伪造完美的证明,同时无声地改变选票。
2019年3月,在伯尔尼,瑞士邮政做了一件听起来像选举透明度黄金标准的事情。其互联网投票系统——由西班牙供应商Scytl构建,打算用于有约束力的瑞士联邦投票——即将在网上公布其完整源代码供全世界阅读。
这正是民主倡导者多年来一直要求的。打开黑箱。让专家查看。通过检查来建立信任。
几周内,三位独立密码学家——Sarah Jamie Lewis、Olivier Pereira和Vanessa Teague——进行了查看。他们的发现并不令人放心。
有人查看前无人看见的陷阱
该系统的核心是一个数学证明。在所有选票被混合和洗牌以保护匿名性后,软件会生成一个密码学"洗牌证明"——一段数学内容,本来应该向任何检查它的人证明洗牌已正确执行且没有选票被改动。
这被称为通用可验证性。理念是:你不必相信服务器。你自己检查证明。
研究人员发现该证明建立在一种称为陷阱承诺方案的东西上。用通俗的英语说:洗牌证明可以被操纵得"验证"正确,即使选票已被无声地改动——只要你知道陷阱值。而陷阱值由系统运营者掌握。
换句话说,知道该值的当局可以生成一份洗牌证明副本,通过验证,同时已重新排列了每一张选票。"通用可验证性"声称从外部是无法证伪的。
他们将论文命名为*"Ceci n'est pas une preuve"*(这不是证明)。
瑞士邮政和Scytl承认了这一发现。瑞士当局暂停了该系统。
教训听起来很专业。其实不然。 只要代码是封闭的,这个缺陷就是无形的。它在代码被打开的那一刻变得可被发现。但找到它仍然需要世界级密码学家花费数周时间。更广泛的问题——这篇文章真正要讨论的问题——是:在"有人可以读代码"和"你能确定读到的代码是机器上运行的代码"之间发生了什么?
瑞士案例打开了代码。但它暴露了一个更深层的漏洞,即使开源也不会自动弥合这个漏洞。
读食谱和品尝菜肴不是一回事
想象一家餐厅公布其食谱。每种材料、每项技术、每个步骤——全部在线、一直在线。
现在想象厨房是上锁的。你可以读到本来应该发生的事。你看不到实际发生的事。
这正是大多数投票软件,甚至开源投票软件的情况。发布源代码是独立验证的必要条件。但这还不够。
原因如下。你在代码库中读到的软件并不是在机器上运行的软件。在"源代码"和"运行程序"之间有一系列步骤:
- 编译器将源代码翻译成机器可读的二进制代码。
- 该二进制文件被打包、安装到投票硬件或服务器上,并进行密码学密封——或不密封。
- 在选举时刻,机器启动并运行其上的内容。
这些步骤中的每一个都是运行代码可能与你检查的源代码产生偏离的地方,且没有任何可见的证据。编译器可以被操纵以插入源代码中不出现的代码。二进制文件可以在构建后被交换。机器可以启动与你认为加载的版本不同的版本。
瑞士陷阱存在于源代码中。但不同的陷阱可能存在于该链中的任何地方——且根本不会出现在代码中。
可重现构建问题,用通俗语言解释
有一门软件工程学科称为可重现构建。其目标很简单:给定相同的源代码、相同的编译器和相同的构建指令,任何运行构建过程的人都应该每次都获得相同的二进制文件——逐字节、逐比特完全相同。
这很重要,因为它给了你一种检查的方法。如果选举当局公布二进制哈希——机器上软件的唯一数字指纹——且如果你能从公布的源代码独立重现该完全相同的二进制,你就有了密码学保证,机器上的代码就是你读到的代码。
如果二进制不匹配,你知道源代码和机器之间发生了什么改变。你不知道什么改变了。但你知道要提出质疑。
没有可重现构建,"检查过的源代码"和"运行软件"之间的漏洞是无形的。你没有工具来检查它。你回到相信做构建的当局。
可重现构建项目——软件工程社区的跨项目努力——已系统地记录了实现这一目标有多难,以及构建链可以通过多少种方式从相同源代码产生不同输出。编译器嵌入时间戳。链接器插入环境变量。文件顺序变化。每一个都是一种机制,通过它两个"相同"的构建可以产生不同的二进制文件,而无人意图欺诈。
证明:问题的第二部分
即使你的构建是可重现的,第二个问题仍然存在。可重现性证明了有人可以从源代码重构相同的二进制文件。它没有证明现在运行在你投票机器上的二进制就是那个二进制。
这就是证明的作用所在。
证明是密码学签署一项声明的过程:"此设备正在运行软件二进制X,在时间T构建,哈希为H。"签名必须来自防篡改的东西——理想情况下来自启动后无法被软件覆盖的硬件,例如可信平台模块(TPM)或硬件安全模块。签署的声明然后可以被任何拥有公钥的人检查。
把它想象成内存卡上的防篡改封条——除了当打开时会撕裂的物理贴纸外,它是一个数学签名,你可以验证而无需相信递给你卡的人。
可重现构建和证明一起形成了一条链:你读源代码→你构建它并获得二进制H→你验证运行中的设备证明二进制H→你确信机器运行的是你读到的代码。
没有那条链,你有两个无关的事实:这是源代码和这是一台运行某些东西的机器。这两件事是否对应是信任问题,而不是验证问题。
"我们运行经过认证的开源软件"是一项声明。可重现构建和证明是使其可检查的东西。
瑞士案例告诉我们深层问题什么
回到瑞士。研究人员发现陷阱是因为他们读了源代码。瑞士邮政承认了缺陷并暂停了系统。到此为止:系统按预期运作。
但注意在该故事的任何报告版本中没有被检查的东西。即使陷阱在源代码中不存在,独立方也没有机制来确认运行在瑞士邮政服务器上的二进制是从该确切源代码编译的——而不是从包含永远不会出现在公开代码中的缺陷的略微修改版本编译的。
这不是假设。2003年,计算机科学家肯·汤普森在其图灵奖讲座中描述了编译器如何可以被修改以自动将后门插入程序——然后进一步被修改以将后门插入它自己,以至于即使从干净源代码编译编译器也会产生受危害的二进制。源代码看起来是清白的。编译器看起来是清白的。输出被特洛伊木马化了。
这不是一个奇异的理论攻击。这是一类众所周知的威胁。对抗它的防御是可重现构建:如果输出是确定性的且已发布,任何独立方可以从源代码重建并检测差异。如果不是——如果每次构建由于无辜的技术原因产生不同的二进制——比较就永远无法进行。
瑞士案例证明了开源优于闭源。它也证明了开源单独是不够的。
我们的漏洞追踪器正在关注的漏洞
在TrustVoting,我们追踪一个特定漏洞:在大多数已部署的投票系统中,缺少公开验证的可重现构建和设备证明。你可以看到这个漏洞出现的频率以及在全球何处。
瑞士系统有开源。它是全民主世界中最透明的互联网投票程序之一。研究人员仍然发现了密码学中的缺陷——这在闭源系统中是无法发现的。即使该缺陷被发现并修复后,独立观察者仍然没有机制来确认服务器上的修补二进制是从修补源代码派生的。
这就是漏洞。它正好位于你能读到的代码和实际处理你选票的软件之间的接缝处。
一些会弥合它的东西:
- 公开发布的构建指令,产生当局声称运行的确切二进制哈希——所以任何技术足够的观察者都可以独立验证。
- 来自每个投票设备上防篡改硬件的签署证明,公布运行二进制的哈希以及每个结果批次。
- 持续的、部署后的监控,对比公布的哈希——所以在认证后但选举日前发生的软件交换将是可检测的。
这些都不是奇异的。它们是高安全软件部署的标准实践。它们在投票系统认证要求中基本不存在。
你今天仍然无法验证什么——以及什么会修复它
这是我们在2019年瑞士事件后留下的不舒服位置。
我们知道开源更好。陷阱被发现恰好是因为代码是可读的。闭源系统会在不被检测的情况下发布缺陷。
我们知道密码学可验证性比单独的纸质记录更好。瑞士系统的整个设计理念——通用可验证性、数学可检查的证明——是为了让投选者确认,无需相信当局,他们的选票被计算了。
我们知道如果不包括源和运行二进制之间的桥梁,两者都不足够。
现在,对于全球部署的几乎每个投票系统,对"我如何知道那台机器上的软件是被审查过的软件?"的诚实回答是:你不能。你相信部署它的当局。
这种信任可能是有根据的。但信任不是验证。德国联邦宪法法院在2009年的裁定中理解了这一点,当时它裁定电子投票只有在普通公民——不仅仅是专家——能独立验证从选票到结果的每个基本步骤时才合法。法院的推理同样直接适用于软件部署和计票:如果确认正确代码正在运行需要相信运行它的人,基本验证步骤就丢失了。
修复不是推倒开源投票努力。而是完成它们。开源加可重现构建加签署证明加公开发布的二进制哈希等于一个系统,其中"你检查过的软件就是运行的软件"对任何有笔记本电脑和好奇心的人都是可检查的——而不仅仅是部署它的当局。
在那条链关闭之前,每一个"我们使用开源、经过认证的软件"声明都是信任的邀请。一个要求你相信它而不是向你展示证明的选举系统,还没有完成解决问题。
资源
- Lewis, Pereira, Teague — Ceci n'est pas une preuve (Scytl-SwissPost互联网投票系统中的陷阱承诺), 2019
- 德国联邦宪法法院,2009年3月3日判决,2 BvC 3/07和2 BvC 4/07(英文翻译)
- Springall, Finkbeiner, Durumeric, Kitcat, Hursti, MacAlpine, Halderman — 爱沙尼亚互联网投票系统安全分析,ACM CCS 2014
- 加州州务卿新闻稿(2018年8月21日):认证洛杉矶县VSAP计票系统为加州首个经认证的开源选举技术
- Halderman, Teague — 新南威尔士iVote系统:一次实时在线选举中的安全失败和验证缺陷,E-Vote-ID 2015 (arXiv:1504.05646)
- Curling v. Raffensperger, No. 1:17-cv-2989-AT, Opinion and Order (N.D. Ga. Oct. 11, 2020), Doc. 964 (Justia)