当前位置: 首页 > 科技观察

Aware,Prevented,Repaired:谷歌提出开源软件漏洞治理框架

时间:2023-03-16 20:23:56 科技观察

1.摘要开源软件的安全问题理所当然地引起了业界的关注,但解决方案需要在实施过程中就挑战达成共识并进行合作.这个问题比较复杂,涉及到很多方面:供应链、依赖库管理、身份识别和构建流水线。如果可以准确定义问题,则可以更快地找到解决方案;为此,我们就业界应如何思考开源软件中的漏洞提出了一个框架(“了解、预防、修复”),列出了需要首先解决的具体问题包括:就元数据和身份标准达成共识。我们需要就解决这些行业复杂性的基本原则达成一致。对元数据细节和识别的共识将促进自动化,减少更新软件所需的工作,并最大限度地减少漏洞的影响。提高透明度并加强关键软件的代码审查。对于安全关键软件,我们需要就开发流程达成一致,以确保充分审查、避免单方面更改并透明地生成定义明确、可验证的生产版本。下面提出的框架和目标旨在激发全行业对开源软件安全的讨论和进步。由于最近发生的事件,软件社区对供应链攻击的真正风险有了更好的了解。因为所有代码和依赖项都可以公开检查,??所以开源软件的安全风险相对较小。这通常是正确的,但前提是人们确实在检查。有这么多的依赖项,监控所有这些是不切实际的,而且许多开源包也没有得到很好的维护。程序通常直接或间接依赖于数以千计的软件包和库。例如,Kubernetes现在依赖大约1000个包。开源软件比闭源软件使用更多的依赖库,并且有更广泛的供应商;因此需要信任许多不同的实体。这使得理解产品如何使用开源软件以及如何找到相关漏洞变得异常困难。此外,无法保证构建的程序将与其源代码匹配。退一步说,虽然供应链攻击是一种风险,但绝大多数漏洞都是平凡且无意的——是出于好意的开发人员无意犯下的错误。此外,恶意行为者更有可能利用已知漏洞,而不是自己发现漏洞,原因很简单,这使得攻击更容易。因此,我们必须集中精力进行根本性的改变,以解决大多数漏洞,使该行业能够深入解决这些复杂问题,包括供应链攻击。几乎没有任何组织能够验证他们使用的所有包,更不用说更新这些包了。就目前而言,跟踪这些包裹需要大量的基础设施和大量的人力开销。我们在Google拥有这些资源,并且在管理我们使用的开源包方面做得很好——包括为我们内部使用的所有开源包维护一个私有存储库——但仍然很难跟踪所有更新。纯粹的更新流可能令人望而生畏。所有解决方案的核心部分是更高程度的自动化,这将是我们2021年及以后开源安全工作的关键主题。因为这是一个需要行业合作的复杂问题,所以我们旨在围绕特定目标展开对话。Google共同创立了OpenSSF,并将其作为此次合作的重点。但要走得更远,我们需要整个行业参与进来,就问题是什么以及如何解决问题达成共识。作为开始,我们提出了解决这个问题的方法,以及我们希望加速全行业解决方案的一系列具体目标。我们建议将这一挑战定义为三个基本独立的问题领域,每个领域都有特定的目标。了解软件中的漏洞防止新漏洞修复或消除漏洞一个相关但独立的问题是提高开发过程的安全性,这对于保护供应链至关重要。我们在第IV节“关键软件的预防措施”中概述了该问题的挑战并提出了目标。2.了解现有漏洞由于种种原因,了解现有漏洞远比想象的要困难。虽然存在报告漏洞的机制,但很难确认特定版本的软件是否受到漏洞的影响。1.目标:获取准确的漏洞数据首先,从所有可用数据源中获取准确的漏洞元数据至关重要。例如,知道哪个版本引入了漏洞将有助于确定某个软件是否受到影响;了解漏洞何时修复可以进行准确及时的修补(并减少潜在的利用窗口)。理想情况下,这种分类工作流程应该是自动化的。其次,大多数漏洞存在于依赖库中,而不是您直接编写或控制的代码中。因此,即使您的代码没有更改,错误也会不断出现、消退和流动。2.目标:为漏洞数据库建立标准架构需要建立基础设施和行业标准来跟踪和维护开源漏洞、了解其后果并管理缓解措施。标准的漏洞架构将允许通用工具跨多个漏洞数据库工作并简化跟踪任务,尤其是当漏洞涉及多种语言或子系统时。3.目标:准确跟踪依赖关系我们需要更好的工具来快速了解哪些软件受到新发现的漏洞的影响,依赖树的巨大规模和动态特性使这个问题变得更加困难。由于软件的版本只能通过安装程序来解析,因此在不实际执行安装操作的情况下,目前很难准确预测调用软件的版本。3.新漏洞的预防理想的方法是防止漏洞的产生。虽然测试和分析工具有帮助,但预防始终是一个难题。在这里,我们关注两个具体方面。在决定采用新的依赖库时需要了解风险。改进安全关键软件的开发过程。1.目标:了解新依赖的风险第一个方面主要是:当你决定使用一个软件包时,你需要了解它的漏洞。接受新的依赖关系会带来固有的风险,因此需要做出明智的决定。一旦使用了依赖库,随着时间的推移通常会变得更难删除。了解漏洞是一个好的开始,但我们可以走得更远。理想情况下,如果没有进行显式更新,依赖库的版本应该是稳定的,但确切的行为因打包系统而异。GoModules和NuGet都是以稳定性而非快速升级为目标的打包系统,它们都默认只在需求更新时安装升级;它只会在更新时被修改。许多漏洞是由于在软件开发过程中未能遵循安全最佳实践而产生的。是否所有贡献者都使用双因素身份验证(2FA)?项目设置是否具有持续集成和运行测试?模糊测试是否集成?这些类型的安全检查将帮助用户了解新依赖项带来的风险。“分数”低的包需要仔细审查和风险缓解计划。OpenSSF最近宣布的安全记分卡项目试图以完全自动化的方式生成这些数据。使用记分卡还可以帮助抵御猖獗的域名仿冒攻击(名称与流行软件包相似的恶意软件包),因为假冒的恶意软件包得分较低并且无法通过许多安全检查。改进关键软件的开发过程不仅与漏洞预防有关,我们将在后续章节中进一步讨论。4.修复或消除漏洞传统意义上的修复漏洞问题不在我们的讨论范围之内,但是对于软件依赖库中的漏洞管理,我们仍然需要做很多工作。虽然它现在没有帮助,但随着我们提高准确性,投资新流程和工具将是必要的。当然,一种选择是直接修复漏洞。如果你能以向后兼容的方式进行修复,那么这个修复对所有人都是可用的。但挑战在于,您不太可能拥有关于此漏洞的专业知识,并且没有办法直接修改它。修复漏洞的前提是软件维护者意识到问题并公开了与漏洞相关的知识和资源。相反,如果你只是简单地删除包含漏洞的依赖库,那么漏洞对你和那些导入或使用你的软件的人来说是固定的,但不是对其他所有人。这是您直接控制的更改。上述场景描述了您的软件和依赖链两端的漏洞,但实际上可能还有许多其他相关包。一般希望链上有人修复。不幸的是,仅修复一个链接是不够的。直到你和错误之间的依赖链中的每个链接都被更新,你的软件才算修复。每个链接必须引用其依赖链下包的固定版本以清除漏洞。因此更新需要自下而上进行,除非您可以完全删除依赖项(这可能需要类似的英雄胆量,并且几乎不可能发生-但在可能的情况下,它实际上是最好的解决方案)。1.目标:了解消除漏洞的选项今天,我们仍然缺乏对流程的清晰了解:其他人取得了哪些进展?应该在哪个级别应用哪个升级过程?进程卡在哪里?谁负责修复错误本身?谁负责传播修复?2.目标:快速修复通知最终,您的依赖关系将得到修复,您可以在本地升级到新版本。但重要的是要知道何时会发生这种情况,因为它可以快速降低暴露于漏洞的风险。此外,我们还需要一个漏洞发现通知系统;一般来说,一个新的漏洞往往意味着一个新的隐藏问题被发现,即使实际代码没有改变(例如Unix实用程序sudo漏洞已有10年历史)。对于大型项目,这些问题大多出现在间接依赖的库中。今天,我们仍然缺乏做一个好的通知系统所需的准确性,所以在我们提高漏洞准确性和改进元数据(如上所述)的同时,我们也应该推动通知系统向前发展。到目前为止,我们只描述了一个简单的案例:一连串向后兼容的升级,这意味着除了错误被消除之外,在行为上没有区别。但在实践中,升级往往无法向后兼容,或者受到版本限制要求的阻碍。这些问题意味着更新依赖树深处的包必然会导致依赖链上游的一些混乱,或者至少导致更新需求项。这通常发生在最新版本(例如1.3)有更新程序,但您的软件或相关软件包需要参考版本1.2时。这种情况很常见,并且成为一个重大挑战,由于难以让开源项目的所有者更新相关包而变得更加困难。此外,如果您在数百个地方使用某个包(这对于大型企业来说并不疯狂),那么您可能需要经历数百或数千次更新过程。3.目标:修复广泛使用的版本修复旧版本中的错误同样重要,尤其是那些使用频繁的版本。这种类型的修复在具有长期支持的软件中很常见,但理想情况下所有广泛使用的版本都应该被修复,尤其是那些包含安全风险的版本。一种自动化的方法可能会有所帮助:给定一个版本的修复,也许我们可以自动为其他版本生成好的候选修复。目前这个过程有时是手动完成的,但如果这个过程被大大简化,我们将能够修复更多??的版本并减少依赖链上游的工作。综上所述,我们需要更方便、更及时地修复漏洞,尤其是依赖库中的漏洞。不仅是最新版本,广泛使用的版本需要更多的机会得到修复,因为最新版本通常包含其他更改,因此很难采用。最后,在“修复”方面还有许多其他选择,包括各种缓解措施,例如避免调用特定方法,或通过沙盒或访问控制限制风险。这些都是重要且可行的选择,值得更多的讨论和支持。五、关键软件的预防措施上述框架广泛适用于各种漏洞,无论是恶意攻击者有意造成的还是无意造成的。虽然之前建议的目标涵盖了大多数漏洞,但仅靠这些还不足以防止恶意行为。为了在防止恶意行为者(包括供应链攻击)方面做出实质性改变,我们需要改进开发过程。这是一项艰巨的任务,目前对于大多数开源项目来说是不切实际的。开源的美妙之处在于,由于没有过程限制,它吸引了广泛的贡献者。但是,这种灵活性会妨碍安全考虑。我们需要贡献者,但我们不能期望每个人都同样关注安全问题。相反,我们必须识别关键包并保护它们。虽然可能会增加开发人员之间的摩擦,但这些关键包必须遵守一套更严格的开发标准。1.目标:为满足更高标准的“关键”开源项目定义标准识别被广泛依赖的“关键”软件包至关重要,它们的丢失可能会危及关键基础设施或用户隐私。因此,这些软件包必须遵守更高的标准,我们在下面概述了其中的一些标准。如何定义“关键”的标准尚不明确,定义的范围可能会随着时间的推移而扩大。除了显而易见的软件包(如OpenSSL或密钥加密库)之外,还有一些广泛使用的软件包值得保护。Google启动了CriticalityScore项目,与社区就此问题集思广益,并与哈佛大学合作开展开源普查。2.目标:禁止对关键软件进行任何单方面的更改我们在Google遵循的原则之一是更改不应是单方面的——也就是说,每个更改都至少涉及一位作者和一位审查者/批准者。目标是限制对手可以自己做的事情——我们需要确保有人真正在检查变化。对于开源项目来说,要做到这一点实际上比在拥有严格认证并执行代码审查和其他检查的公司内部要困难得多。避免单方面的改变可以分解为两个子目标。(1)目标:要求对关键软件进行代码审查。代码审查不仅是改进代码的好方法,而且可以确保每个更改都至少由除作者以外的其他人检查。代码审查是谷歌内部所有变更的标准做法。(2)目标:对关键软件的更改需要两个独立方的批准。要真正达到“有人检查”的目的,我们需要审查者独立于代码贡献者。对于重大变更,我们可能需要不止一次的独立审查。当然,我们需要梳理一下到底什么是“独立”审查,但独立的理念对于大多数行业的审查来说都??是至关重要的。3.目标:验证关键软件参与者独立性的概念通常意味着您了解参与者——匿名参与者不能被认为是独立的或值得信赖的。今天,我们基本上使用别名:同一个人一遍又一遍地使用相同的身份来建立声誉,但我们不知道那个人是否值得信赖。这导致了一系列的子目标。(1)目的:对于关键软件,拥有者和维护者不能匿名。攻击者喜欢匿名。在过去的供应链攻击中,攻击者利用匿名并通过包社区成为维护者,而没有人意识到这个“新维护者”有恶意(侵入性代码最终被注入上游)。为了减轻这种风险,我们认为关键软件的所有者和维护者不能是匿名的。可以想象,与所有者和维护者不同,贡献者可以保持匿名,但前提是他们的代码已通过受信任人员的多次审查。还可以想象,我们可以拥有一个“经过验证”的身份,即:一个受信任的实体知道他的真实身份,但出于隐私原因,公众并不知道。这将促进有关独立性和起诉非法行为的决策。(2)目标:为关键软件的贡献者提供严格的身份认证。恶意攻击者寻找容易攻击的媒介,因此网络钓鱼攻击和其他形式的凭据盗窃很常见。一个明显的改进是需要双因素身份验证,特别是对于所有者和维护者。(3)目标:联合身份模型为了在开源中继续具有包容性,我们需要能够信任各种各样的身份,但可验证的完整性仍然是必不可少的。这意味着身份的联合模型,可能类似于我们今天支持联合SSL证书的方式——多方可以生成有效证书,但必须有严格的审计和相互监督。OpenSSF的数字身份工作组已经开始讨论这个话题。(4)目标:风险变化通知为了覆盖风险的变化,我们应该扩大通知的范围。最明显的是所有权的改变,这可能是新攻击的前奏(比如最近的NPM事件流泄露事件)。其他示例包括发现被盗凭据、串通或其他恶意行为者。(5)目的:增加工件的透明度。安全哈希通常用于检测工件是否完好无损,数字签名用于证明真实性。添加“透明度”意味着这些证明是公开记录的,记录了所有意图。反过来,外部各方可以监控假版本的日志,即使用户没有意识到这一点。更进一步,当凭据被盗时,我们可以了解这些凭据用于签署哪些工件并尝试删除它们。这种透明度,包括持久公共日志记录和第三方监控,已成功应用于SSL证书,我们为包管理器提出了类似的方法。知道您正在使用正确的包或二进制文件类似于知道您正在访问网站的真实版本。(6)目标:信任构建过程1984年,肯·汤普森(KenThompson)著名的图灵奖演讲证明,仅靠真实可信的源代码是不够的,最近的事件表明,构建过程攻击也是一个真正的威胁。你如何验证你的构建系统是可信的?它的所有组件都必须通过持续的信任建立过程得到信任和验证。可重现的构建会有所帮助(具有确定性结果的构建,由此我们可以验证我们的构建是否正确),但由于时间戳等临时数据最终会出现在构建的发布中,因此这很难实现。安全和可重复的构建需要验证工具,而验证工具又必须是可验证和可重复的构建,等等。我们必须建立一个可信赖的工具网络并构建产品。可以通过“委托”(上述透明过程的一种变体,称为二进制授权)建立对工件和工具的信任。在Google内部,构建系统对所有工件进行签名并生成与源代码相关联的清单。对于开源项目,一个或多个受信任的代理可以将构建作为一项服务运行,签署工件以证明他们对其完整性负责。这种生态系统是应该存在的,而且在大多数情况下,我们只需要大家意识到这一点,并以证明文件的形式签署一些协议,我们就可以安全地将上述过程自动化。本节中描述的措施非常适合一般软件,现在已在Google内部广泛使用,但对于开源项目而言,它们的工作量要大得多。我们希望通过专注于少数关键软件来实现这些目标,至少在关键软件上。随着工具和自动化的改进,这些目标将得到更广泛的采用。6.总结开源的本质要求我们通过共识和协作来解决问题。对于像漏洞这样的复杂主题,这意味着围绕关键问题展开讨论。我们为这次讨论提出了一种框架方法,并定义了一组目标,我们希望这些目标将加速整个行业的讨论并导致最终的解决方案。第一组目标广泛适用于漏洞,本质上是关于自动化和减少风险和工作量。原文链接:https://opensource.googleblog.com/2021/02/know-prevent-fix-framework-for-shifting-discussion-around-vulnerabilities-in-open-source.htm