一、执行摘要
• 元数据和身份标准共识:行业需要就解决这些复杂问题的基本原则达成共识。在元数据细节和身份方面统一看法后,将推动自动化,减少更新软件所需的工作量,并将漏洞的影响降至最低。
• 提高关键软件的透明度,加强对这些软件的审查:对于对安全至关重要的软件,我们需要就开发过程达成一致,确保充分审查,过程透明,避免单方面更改,最终产生语义清晰的可验证官方版本。
以下框架和目标的提出旨在引发业界对开源软件安全的讨论,促进开源软件的安全。
鉴于最近发生的多起事件,软件界切实感受到了供应链攻击的风险实实在在地存在着。开源软件在安全方面的风险应该较小。因为所有代码和依赖项都是开放的,可供检查和验证。总的来说,这种看法没什么问题,但它的前提是确实做了检查。要全面监控这么多的依赖项不太现实,而且许多开源软件包并没有得到妥善维护。
一个程序通常直接或间接地依赖于数千个软件包和库。例如,Kubernetes现在就有约1000个依赖包。开放源代码可能比封闭源代码的依赖关系更多,并且来自更广泛的供应商;需要信任的实体数量巨大。这样,就很难弄清楚开放源代码在产品中的使用情况以及哪些漏洞事关重大,同时也无法保证生成的内容与源代码匹配。
退一步讲,尽管存在供应链被攻击的风险,绝大多数漏洞都是善意的开发人员的无心之失。此外,攻击者更可能利用已知漏洞,而不是寻找新漏洞:显然前者更简单。因此,我们必须集中精力进行根本性的变革,堵住大多数漏洞,进而推动整个行业取得进步,有效解决复杂问题,包括供应链攻击。
很少有组织能够验证自己使用的所有软件包,更不用说这些软件包的所有更新了。在当前情况下,跟踪这些包需要大量的基础设施和大量的手动工作。谷歌拥有这些资源,同时尽自己所能管理所使用的开源软件包(包括对内部使用的所有开源软件包建立私有库),但要跟踪所有更新仍颇具挑战。光是上传下载这些更新就令人望而生畏。无论什么方案,解决这个问题的核心都是提高自动化水平,这将是2021及以后我们开源安全工作的一个重要主题。
由于这个问题很复杂,需要行业合作,本文仅围绕具体目标展开。谷歌联合创建了OpenSSF,聚焦于解决这一问题,但要取得进展,需要整个行业的参与,就问题所在以及如何解决这些问题达成一致。为抛砖引玉,我们提出了一个讨论办法以及一系列具体目标,希望通过这些目标加速全行业的解决方案研发。
我们建议将挑战分为三个基本独立的问题领域,每一领域都有自己的具体目标:
1. 了解软件中存在的漏洞
2. 预防新漏洞的出现
3. 修复或删除漏洞
提高开发过程的安全性是一个相关但独立的问题,对于确保供应链安全至关重要。我们在第四节“关键软件的预防措施”中概述了此问题带来的挑战并提出了目标。
二、了解漏洞
其次,大多数漏洞都存在于依赖项中,而不是自己所编写或控制的代码中。因此,即使自己的代码并未改动,漏洞也会不断发生变化:有被修复的,也有新引入的。
三、预防新漏洞
• 在决定引入新的依赖项时提前了解风险;
• 改进关键软件的开发过程。
首要的是要了解漏洞,但这还远远不够。
许多漏洞之所以存在是因为软件开发过程中未遵守安全最佳实践。是否所有参与者都使用了双因素身份认证(2FA)?项目是否有持续集成设置和运行测试?是否集成了模糊测试?这些都是安全检查类型,可以帮助消费者了解新引入的依赖项中所面临的风险。得分较低的软件包需要进一步审查,并制定补救计划。
OpenSSF最近宣布的安全记分卡项目旨在以全自动方式生成这些数据点。使用记分卡还有助于抵御猖獗的Typosquatting(名称与常用软件包相似的恶意软件包)攻击,因为这种软件包的得分要低得多,无法通过多数安全检查。
改进关键软件的开发过程与漏洞预防相关,但需要进一步讨论,所以将在后文详述。
四、修复或删除漏洞
当然,最直接的方法是修复漏洞。若采用的是向后兼容方法,那么这一修复会惠及所有人。但问题是,你可能并不具有相关专业知识,也无法直接做出改变。修复漏洞的前提是软件维护人员知道漏洞的存在并拥有漏洞披露所需的知识和资源。
相反,如果你干脆删除了包含漏洞的依赖项,这种修复便对自己的软件以及导入或使用这个软件的其他人有效,但不会惠及所有人。这一更改由软件所有者直接控制。
上述场景代表了自己的软件和漏洞之间依赖关系链的两端,但实际上中间可能存在多个软件包。人们都指望依赖关系链上的某个人能够修复漏洞。然而,只修复单个环节是不够的:要更新自己和漏洞之间依赖关系链的所有环节,才能修复自己的软件。每一环节都必须修复之前环节的版本漏洞,这样才能彻底清除漏洞。因此,更新需要从下到上进行,除非能完全消除依赖项,这个办法需要勇气,也几乎不可能,但若可能的话,则是最佳解决方案。
到目前为止,我们只描述了一种简单情况:升级都是向后兼容的,这意味着除了没有漏洞之外,行为相同。
实际上,升级通常不向后兼容,或者受限于限制性版本要求。这些问题意味着更新依赖树深处的软件包必然会导致上面的内容发生变化,或者至少要更新要求。常见例子是,修复了最新版本(比如1.3版本),但自己的软件或中间软件包要求使用1.2版本。这种情况并不鲜见,如今仍是一大挑战,尤其是很难让软件所有者更新中间软件包。此外,如果一个软件包用在一千个不同的地方(这对于大企业来说很正常),那么可能需要经历一千次更新过程。
自动化能促进这项工作:得到某一修复版本后,也许我们可以为其他版本生成有效的修复方案。目前,这个过程有时通过手工完成,但如果我们能大大简化这一过程,那么实际上能够修复更多版本,这样,在依赖关系链上端需要做的工作就会减少。
总而言之,我们需要使用多种方法来简化并加快漏洞修复,尤其是依赖项中的漏洞。对于广泛使用的版本,需要尽可能进行修复,而不仅仅是修复最新版本,因为最新版本可能包含一些其他程序无法兼容的变更,导致无法采用。
最后,在“修复”方面还有许多其他方案,包括各种缓解措施,如避免某些方法,或通过沙盒或访问控制抑制风险。这些方案也很重要且可行,需要进一步讨论,得到更多支持。
五、关键软件的预防措施
这是一项艰巨的任务,尤其是对于现今大多数的开源软件而言,很难实现。开源的其中一个优点是对过程没有限制,这鼓励了各类人群的广泛参与。然而,这种灵活性可能会影响安全。我们需要贡献者,但我们不能指望所有人都对安全给与同样的关注。我们要做的是识别关键软件包并加以保护。这类关键软件包必须遵守更严格的开发标准,即使这会让开发人员心存抵触。
如何定义“关键”并非易事,而且定义还可能会随着时间的推移而扩展。除了OpenSSL或密钥加密库等众所周知的软件外,还有一些广泛使用的软件包,它们的覆盖范围之广决定了它们必须得到保护。我们启动了关键性评分项目,与社区集体讨论这个问题,并与哈佛大学合作开展开源普查工作。
“避免单方面更改”可拆分为两个子目标:
与所有者和维护者不同,贡献者可以匿名,这可以理解,但前提是他们的代码通过了可信方的多次审查。
同样,我们可以拥有“经验证”的身份,其中一个可信实体知道我们的真实身份,但出于隐私原因,不透露给公众。这有助于做出关于独立性的决定,对非法行为进行起诉。
OpenSSF的数字身份认证工作组已开始就此展开讨论。
构建若可复制,便能产生确定结果,有助于确认可信性。然而,由于发布工件中存在临时数据(如时间戳),可复制又很难实现。安全的可复制构建需要验证工具,而这些工具又必须以可验证和可复制的方式构建,这样循环往复。我们必须构造一个可信工具和构建产品网。
工件和工具信任都可以通过“委托”来建立,而委托通过上述透明过程的一个变体实现,称为二进制授权。谷歌内部的构建系统对所有工件进行签名,并生成清单,将工件与源代码关联起来。对于开放源代码,一个或多个可信代理可以将构建作为服务运行,对工件进行签名,证明工件的完整性。这种生态系统应成为现实,在大多数情况下,还需要培养意识,就证明格式达成一致,以便安全地对过程进行自动化。
总体上,本节中的操作对于软件安全极为有益,如今在谷歌内部广泛采用。而对于开源来说,这些操作更为重要。我们希望,至少可以针对关键软件实现这些目标。随着工具和自动化水平的提高,这些目标将会更容易实现,可望普遍推行。
六、总结
漏洞管理的一般目标
针对关键开源软件的目标
原文作者:Eric Brewer,Rob Pike,Abhishek Arya,Anne Bertucio,Kim Lewandowski
免责声明:该文章原文版权归原作者所有。文章内容仅代表原作者个人观点。本译文仅以分享先进网络安全理念为目的,为业内人士提供参考,促进思考与交流,不作任何商用。如有侵权事宜沟通,请联系littlebee@nsfocus.com邮箱。