开源软件包

防范开源恶意软件:哪些方法有效(哪些方法无效)

这是 系列文章 最常见的软件供应链攻击是滥用公共注册表的攻击 开放源码 软件组件。在上一集分析之后“恶意软件包剖析:有哪些趋势?”不良行为者如何将恶意行为注入新的或现有的已发布组件中,我们已准备好穿上消防服,研究如何成功阻止以这种方式传递的恶意软件,或者另外处理由于我们采取了错误的方法而可能引发的严重网络事件。

大多数有安全意识的专业人士都知道如何应对这种威胁。我们听到安全经理毫不犹豫地说 SCA 工具已经告诉您软件包版本是否是恶意软件。或者它们依赖于知名的、经过高度审查的软件组件,任何恶意软件都会被迅速检测和删除。它们使用开放的次要/补丁版本来自动获取漏洞修复,这是降低开源依赖项风险的正确、推荐的方法,遵循“早打补丁,经常打补丁”原则。 

在本期节目中,我们将回顾这些想法为何是错误的,以及这些误解如何导致这种攻击机制的流行,以及组织正在经历的巨大风险。我们将以哪些方法有效以及需要付出哪些努力和资源作为结尾。

常见误区

在我们研究软件安全的过程中,我们看到攻击技术在不断发展,安全意识强的人也提出了各种各样的想法。组织经常误解什么方法可以抵御这种威胁,因此我们首先来研究一下什么方法行不通,下面列出了一些误解,但这些误解并不详尽。

误解1: SCA 工具已经报告恶意组件

的确如此! 但事后…如果该元素在软件构建中使用,可能为时已晚,而恶意行为者已经在开发人员或 CI/CD 主机。机密可能已被泄露,其他恶意软件可能已被下载和安装,而且对手可能横向移动并已在其他地方获得访问权限。 

软件组成分析(SCA) 工具旨在识别潜在的已知漏洞。现代工具通过增强信噪比,确定漏洞是否真正可访问或可利用,从而发挥了重要作用。但它们对新恶意软件毫无用处。将恶意组件视为零日漏洞:只有当检测到其恶意行为时,才会将该组件报告给持有注册表,经过安全团队的审查后,确认其为恶意组件并从注册表中删除 [1]

到那时,世界(包括 SCAs) 知道安装或使用该组件(或现有组件的某些版本)不是一件好事。但这是当注册表中没有该组件时。知道第三方组件存在漏洞,甚至被注册表归类为恶意的组件存在漏洞是件好事,但不幸的是 SCA 或者常见的审计工具在这种情况下没有帮助。 除非 SCA/审计工具确实可以在您的组织使用某个组件之前提前知道它是否是恶意的.

请记住,任何针对恶意开源组件的解决方案都必须检测它们 即时,即组件在注册表中发布和组件(版本)首次在您的组织中使用之间的时间间隔。其中包括传递组件。  

误解 2:在构建时控制安装脚本可以防止开源组件的恶意行为

各种包管理器都提供了运行脚本的功能(包含在组件 tarball 中 [2]), 出于合法原因,例如在不同平台上编译所需项目、生成代码或运行测试,并且我们都应该知道,如果 tarball 中包含恶意脚本,或者攻击者可以运行恶意脚本而不是好脚本,那么它们可能会被不良行为者滥用。

了解了这一点,我们可以配置包管理器以忽略脚本。例如,使用 NPM –忽略脚本 标志(或配置属性 .npmrc 文件)在安装过程中跳过脚本。这可能会产生一些问题,因为运行脚本在许多生态系统中很常见:一些包管理器甚至不允许禁用脚本执行(提示:提示“哪些包管理器不允许禁用安装脚本的执行?”在你最喜欢的 AI 中)。但这并不能起到一般性的保护作用(我们需要强制到处都设置跳过禁用配置)。 

当恶意行为不是位于安装脚本中而是位于运行时执行的软件中时,仅靠这个选项并不能保护我们。 

误解 3:版本固定可防止安装恶意组件

尽早和经常修补与 开放版本 (让包管理器在有安全修复可用时自动安装新的更新)和 版本固定 (具有固定版本的软件的所有直接和传递依赖项)。安全原则是顽固的,有时甚至相互矛盾,例如“尽早修补,经常修补”和 “升级不容掉以轻心”。一些包管理器会按照推荐的方式自动更新服务器范围。如果您也想接收恶意更新,这很棒!是的,必须更新组件才能尽快接收修复漏洞的安全修复程序,但是……永远不要让包管理器自动执行此操作。

误解 4:使用受信任的组件是安全的。任何恶意版本都会被及时发现、披露和删除。

为什么组件值得信任?可能是因为它非常受欢迎,有很多人关注漏洞,有大量的贡献者进行维护,有多个核心维护者认真审查所有 pull requests实际情况则大不相同。一些基本组件由单个无薪开发人员维护。广泛使用的框架 一些定期撰稿人,数量迅速减少 commit每个维护者(热门项目有一大批贡献者,他们会做一些驱动 commit 并且永远不会回来)。而且只有一个维护者的流行项目比比皆是。

想象一下自己说 “哦,我们正在使用 Spring Boot / Angular / React / PyTorch / 官方基础 Docker 镜像,所以你所说的风险非常低。” 也许这是真的,我们安全供应商一直在散布恐慌,而干涉开发团队以减轻有争议的风险是无稽之谈。你可能会想跳到风险接受段落(在下一节中),然后就大功告成了。不幸的是,最流行的组件是坏人的目标,例如,流行的 PyTorch 库遭到攻击 在过去的。

“及时发现、披露、删除”。  新的恶意组件需要几天时间才能从公共注册表中删除。注册表对于删除组件版本非常谨慎,这是为了好。我们的经验是,一旦我们报告,注册表删除受影响版本的平均时间为 39 小时,超过一天半。有些恶意组件在我们首次报告后一周才被删除。在某些情况下,只有在受害者或事件响应公司报告涉及该组件的事件后,该组件才会被删除。 

哪些方法对付不了恶意组件

任何不具体的方法都会以失败告终。这是肯定的,因为你没有针对与此威胁相关的风险提供有效的对策。 

传统 SCA 工具会告诉您有关已知恶意软件的信息,但暴露窗口很大。除非它们主动执行恶意软件检测并强制阻止恶意组件,否则它们无法抵御这种威胁。 

禁用安装脚本可能会有所帮助,但需要在需要安装组件的任何地方强制执行。版本固定也是如此,因为版本不能永远固定在安全的初始状态。

假设流行的组件得到足够的关注,以至于它们不会在供应链攻击中被注入意外​​行为,而无需几乎立即检测以防止任何损害,这是天真而危险的。你不想生活在边缘,是吗?

如果你在此时停下来,那么 风险承受能力 你唯一能做的是:这是一个cis需要记录在威胁模型/风险评估中的因素,包括接受风险的理由及其潜在影响。通过与管理层和其他相关方沟通来提高认识。一些 偶然性 可以在安装或包含恶意组件时进行规划,但这很难,因为攻击者有很多路径可循。基于使用恶意组件的供应链攻击的细节将极大地改变事件的公开披露,这可能是贵组织的监管框架强制要求的。您也可以解决 补偿控制 or 转移风险 例如保险。

但是,有一些控制措施可以解决威胁,如果您对风险接受度不满意,则应考虑这些措施。请继续阅读。

什么可以抵御使用恶意组件的攻击

实体版本处理

版本锁定和受控且知情的版本变更是可行的方法,可以平衡消除漏洞的需求而不接收恶意软件。但请记住误解 3:仅靠版本锁定不足以阻止来自新版本的恶意代码,因为您将来需要更新任何直接或间接依赖的版本。那时您需要足够有力的证据来证明所有修改后的版本都不包含恶意软件。

预先警告

解决恶意组件问题的一种方法是使用预警系统(本文将其命名为 恶意软件预警 或 MEW),其中发布的新版本(针对新的或现有的组件)由检测引擎进行分析,当发现足够的证据时,检测引擎可能会将新版本归类为潜在的恶意软件。 

自动化在这里至关重要,因为以目前的发布速度不可能手动审查所有新组件。因此,检测引擎需要结合多种技术,可能包括静态、动态和功能分析、用户声誉以及来自组件元数据和 tarball 内容之间差异的证据,或者 tarball 和组件可能来自的源存储库之间的差异的证据。

有一个 暗区 发布时间和引擎分析组件内容的时间之间间隔不大,但不应超过几分钟。可以修改该方案,例如等待新组件被分析后再允许它们在软件构建中安装和使用 pipelines,或者在需要时按需分析它们。给定版本的组件是不可变的 [3],因此仅需分析一次。

完全自动化是不可能的,并且需要对潜在的恶意组件进行安全审查。 警惕数字万能药的支持者:在确认可疑组件是否含有恶意软件时,人工智能和机器学习还不够发达,无法做出最终判断。当然,机器学习在检测引擎中扮演着关键角色,可以将输入组件与捕获的原始证据进行分类,但一旦组件被“隔离”,最终决定权就落在了有恶意组件经验的安全团队的人工审查上。这将确认任何潜在的恶意软件或将其重新归类为安全。时间段在几小时范围内。 

注册中心报告恶意版本/组件;然后注册中心进行审查以确认,并进行公开披露和从注册中心删除。一些注册中心会保留安全保留包。这里的时间范围是自发布以来的几天或几周,即“停留时间' 要么 '曝光窗口对于大多数恶意组件来说。

是否有可能知道组件版本是否是恶意的?

因此,为了进行早期预警,我们需要对这个问题给出令人满意的答案:我如何知道一个库或包是(不是)恶意的?如何收集足够的恶意行为证据?有可能,但很困难,因为对手会使用很多聪明才智来避免被发现。有不同的方法,每种方法都有优点和缺点。

静态分析 可以检查所有执行路径,检查攻击者使用的技术,而无需运行组件,并执行反混淆或解密等预处理任务。当攻击者试图隐藏他们的恶作剧时,混淆尝试确实是恶意软件的证据(但请注意,合法组件会混淆代码以保护知识产权,这与“开放源码”)。只有少数高度复杂的攻击需要沙盒处理,但这种高度混淆是恶意行为的明显迹象。请注意,传统的 SAST 工具的设计目的是为了解决无意的漏洞,而不是为了解决后门等恶意问题。

动态分析 运行组件并通过检测运行时(通常通过提供沙盒环境)来检查响应。在某些条件下触发的恶意行为可能会被忽略:请注意,恶意软件可能会使用规避技术,例如 虚拟化/沙盒规避 仅在不受审查时激活,也是任何静态分析引擎的恶意活动的迹象。

能力分析 考虑组件的作用:它连接到哪里、访问哪些文件、运行哪些命令或程序、执行了哪些终端或设备 I/O 或调用了哪些系统调用。这种行为指纹识别可以跨版本进行比较(对于现有组件),因此当检测到意外行为时,该证据可能会引起对新版本中注入的潜在恶意活动的怀疑。这种方法遵循安全分析师在面对潜在恶意软件时遵循的分类步骤:使用 字符串 或类似工具。无论触发条件如何,此方法都可以检测恶意行为,并且在没有源代码的情况下也能发挥作用。

上下文分析 收集有关组件如何发布以及由谁发布的信息。不良行为者的攻击活动通常使用未经任何严格审查过程的新用户帐户。跟踪过去的活动可能会深入了解潜在用户,主要是针对可能暗示潜在危害的异常情况。声誉很难获得,却很容易失去!没有过去活动的用户是中立的,但因果报应会追随恶意者。黑客活动分子或发布凭据被盗的普通用户应受到仔细跟踪。

另一个上下文信息是用于创建组件 tarball 的源存储库与 tarball 本身的内容之间的任何差异。此外,还要遵循良好的做法,例如在源存储库中创建与公共注册表中发布的组件版本相匹配的标签或版本。当源存储库处于特定状态时 commit 被标记为 release,然后突然有一个版本无法跟上,这本身就是组件可能被污染的有力证据:恶意行为者可能已经破坏了用于发布组件的帐户,但没有源代码存储库的写入权限)。许多攻击都是使用这些规则定期检测的:例如, 账本攻击 按照这种思路,很容易发现异常。因此,上下文分析可以在出版过程中识别出此类异常。

依赖防火墙

另一种方法是针对软件中使用的所有依赖关系图建立全面的组件白名单,因此在任何构建中 pipeline 在您的组织中运行的组件版本只能安装和使用已批准的组件版本。“火墙” 使用内部注册表强制执行,其中提供(缓存或代理)允许的组件版本的 tarball。请注意,除非您拥有将任何新版本归类为合理安全的技术,以便可以将其添加到白名单中,否则任何白名单都将不起作用。 

请注意,早期预警(新版本发布后尽快快速检测)需要与某种方式相结合,以主动使用该信息来阻止影响构建的组件 pipeline或开发人员的机器 [4]。我们称之为“依赖防火墙”:一种保护自动构建免受恶意软件攻击的隔离机制。内部软件包和镜像注册表可以很好地保护组织免受外部邪恶的侵害,但需要足够有力的证据才能使隔离有效。 

运行时沙盒

在发布时进行检测的另一种方法是分析运行时的行为。这个想法是从软件中捕获预期的行为并检测(或阻止)发现的任何异常。这种做法存在必须对运行时进行监控或阻止的问题,这是一个很有前途的想法,将被添加到针对恶意组件害虫的保护机制库中。

制定全面的战略

建议的策略需要在软件开发过程中结合不同的技术,控制版本更新以阻止传入的恶意组件。我们必须适应版本固定,以避免自动感染,更新版本以修复重要的漏洞;在版本更新期间快速有效地评估直接和间接依赖关系,以获得足够的证据证明它们没有受到恶意软件的侵害。依赖已知恶意组件的软件版本必须被阻止。所有这些都必须执行。

尽可能使用版本固定,因为它使构建更具可重复性。 通过受控、手动批准的版本升级来实现版本固定辅助技术,应该评估更新是否会带来恶意软件或破坏软件,并协调修复漏洞的更新与避免恶意软件感染。工具可以在这里提供帮助,通过以下方式:(1)确定真正重要的漏洞的优先级(可触及和可利用,被攻击者作为目标的高风险),(2)选择与当前组件使用兼容且不会破坏软件的目标版本,(3)选择不包含恶意行为的目标版本,以及(4)通过在清单文件中建议可以快速批准的更改,使直接和间接依赖项的版本更新变得轻而易举。步骤(3)需要尽可能接近恶意组件的发布时间的具体信息。

更新依赖项的过程必须是 强制执行专利 在所有地方。必须记录该过程,并应对所有相关方进行培训,因为开发和软件构建/部署通常都是外部化的。 CI/CD pipeline应该进行相应的修改,以便自动化不会允许恶意的间接依赖进入构建: guardrails 如果有足够的证据表明依赖项中存在潜在恶意软件,则建议阻止构建。 

如果您的组织有一个内部注册表作为保存允许的组件版本的安全代理,则您必须在将请求的组件添加到允许列表之前,获取有关恶意组件的情报(除了其他标准)以审查请求的组件。 

安全地使用开源软件并不容易,必须充分考虑恶意软件因素,并在漏洞处理方面付出同样的努力。

最后一点: 来源出处以软件证明的形式,在组件构建时生成,是追踪工件(组件 tarball)及其生成源和构建过程的另一个关键部分。请注意,源快照 + 构建环境与相关软件工件(由受信任的构建系统签名)之间的这种链接并不能阻止组件本身不包含恶意行为,但会使坏人更难注入恶意软件。将出处验证作为使用开源组件的常见要求将需要很长时间,而且只有 最近添加到 NPM使这些受信任的构建和部署系统防篡改,或能够检测构建中的任何篡改行为是另一回事,超出了本文的讨论范围。 

深入阅读

下一集 开源恶意软件:Xygeni 方法 将介绍我们在 Xygeni 遵循的战略 恶意软件预警 (MEW)系统。扫描公共软件包和镜像注册表中的新软件包版本,并使用静态、动态、功能和上下文分析的组合获取证据。结合用户信誉和源代码存储库中的更改历史,可以将组件完全自动分类为高风险和可能恶意的类别。系统从过去从软件包中收集的证据中学习,以将误报率降至最低。 

当某个恶意版本被归类时,订阅的组织会收到有关他们直接或间接使用的组件的警告通知。然后,我们的分析师会进行手动分析,确认或拒绝分类。对于已确认的恶意软件,公共注册表会收到通知,以便其可以自行进行分析,并通常删除恶意版本或采取其他措施,例如阻止或删除相关用户帐户。

我们将解释我们如何帮助 NPM、PyPI、GitHub 和开源生态系统中的其他关键基础设施减少新发布的恶意组件在被确认为恶意软件并从注册表中删除之前保持活跃的停留时间。以及组织如何从 MEW 系统中受益,从而更好地防范涉及开源组件的软件供应链攻击。

  • [1] 无论如何,组件的用户需要检查组件 tarball 是否被缓存或在某处注册,例如在内部注册表中,这样才能消除弊端。
  • [2] 打包的组件包含一份清单,其中声明了组件的内容和元数据、源代码或编译后的代码、安装脚本以及测试套件等附加项目,这些内容均符合打包格式,通常采用压缩格式。这被称为“组件 tarball”。
  • [3] 即使恶意行为者能够由于注册表本身的漏洞而修改已发布的组件,但分析完成后,普通的加密摘要仍能检测到 tarball 中的任何变化。
  • [4] 请记住,某些恶意组件会在安装时运行,因此它可能会影响在不知情的情况下使用恶意组件 X 运行“npm install X”的开发人员节点。  

开源恶意软件:问题

恶意软件包剖析:有哪些趋势?

sca-tools-软件-成分分析工具
确定软件风险的优先级、进行补救并加以保护
注册免费账号。
不需要信用卡。

保护您的软件开发和交付

使用 Xygeni 产品套件