依赖混淆版本固定

缺乏版本锁定和依赖混乱

在软件开发中,我们既依赖自己的组件,也依赖第三方的组件或工件。灵活的依赖管理对于现代软件至关重要。NPM 等包管理器 Maven的点子 or 的NuGet 通常用于指定软件依赖关系。这些工具的设计考虑的是便利性和易用性,而不是安全性。

 

该问题

问题在于,灵活性和易用性吸引了开发者的注意,而坏人则认为软件依赖性对他们的业务具有不可抗拒的吸引力。结果:坏人遵循了这里显示的所有可能的攻击路径。来源:“背叛者的利刃集合:开源软件供应链攻击回顾”

在本文中,我们将重点介绍开放版本声明的使用,即下载的版本不是固定的,而是必须属于某个范围。在构建时,包管理器将选择并下载/安装与指定版本范围兼容的最高现有版本。

让我们说明一下不同包管理器的依赖项声明中的开放声明:

      • 新产品管理: 的package.json

    {

     

       ...

       “依赖项”:{
          ...
          “接受”:“> = 1.3.8”,
          “lodash”:“~4.16.0”,
          ...
       },
       ...
    }

    将安装 accepts 包的现有最大版本(不低于 1.3.8),以及 4.16.x 范围内 lodash 的最大“补丁”更新。

        • 马文: pom.xml

      ...

      ...

           commons-io
           commons-io
           发布

      ...

      ...

      适用于 commons-io(jar 文件)的最后一个可用版本将作为依赖项添加。

          • PIP: 设置文件

        ...
        设置(
            ...
            install_requires=['peppercorn','launchpadlib'],
            ...
        )
        ...

        这种开放版本方案有好的一面,也有坏的一面。好的一面是,较新的版本 平时 包含功能和质量改进、错误修复和安全补丁,这些都会自动升级。请注意,对于大多数实际项目,修复不会反向移植到以前的次要版本,除非是灾难性的安全漏洞。开放版本也适用于库,以减少在解决所有依赖项时需要安装的版本数量。

        但开放版本范围也有不好的一面。你不知道在构建时会安装哪些版本,而且构建不可重复。此外,还有一个 黑暗 开放版本。如果恶意行为者设法在公共存储库中发布与您的开放范围兼容的高版本的恶意组件,您的下一个版本将包含恶意组件,甚至可能在可能自动执行的安装脚本中执行恶意软件。混淆攻击负载是一门艺术。

        这就是所谓的 缺乏版本固定 问题。

        不法分子总是试图将流行的开源软件包的恶意版本发布出来。他们可能会在秘密泄露中获取软件包存储库的密钥;他们经常使用社会工程学或将嵌套的恶意依赖项隐藏在看似有用的 pull request甚至一些作家自己有一天也会觉得这个世界不公平,并对他们的客户进行 抗议软件 在他们自己的包裹里!

        现在想象一下,您正在为一个使用内部组件和开源组件的组织工作。
        如果恶意攻击者知道此类内部组件的名称,他/她就可以设法在公共存储库中发布同名组件。许多包管理器首先获取公共组件,如果版本选择正确并且声明的依赖项中的版本是开放的,那么问题就来了!此问题名为 依赖混乱.

        让我们举个例子。假设在我们的 NPM 项目中,我们对一个私有组件有依赖关系:

            • 新产品管理: 的package.json

          {
            “名称”:“我的项目”,

           

            ...
            “依赖项”:{

              ...
              “我的私有依赖”:“>=1.0.0”,

              ...

             }

             ...

          }

           

          攻击者可能会创建 my-private-dep 的高主版本(如 99.0.0),并使用自己的虚假帐户将其发布到公共 npm 存储库中(攻击者无需对我的组织进行任何操作)。NPM 包管理器将安装恶意依赖项,通常会带来灾难性的后果。

          解决方案

          为了避免在软件构建过程中出现这些问题,我们应该遵循严格的规范,根据所使用的技术声明组件版本。重要的是,一旦在存储库中发布,软件包的特定版本就应该是不可变的(以避免破坏依赖项,而不仅仅是出于安全原因)。

          一般的想法是注视() 版本,始终检查组件的固定版本(包括所有传递依赖项)是否不含恶意软件,这要归功于 锁文件 许多包管理器都提供此功能。让我们看看不同包管理器的版本锁定功能是如何工作的。在以下两者之间存在微妙的权衡: 频繁的版本更新 修复已知漏洞和 版本固定 以避免非确定性构建和潜在的供应链攻击。

              • NPM:
                npm 或 yarn 包管理器使用不同的锁文件(分别为 npm-shrinkwrap.json / package-lock.json 或 yarn.lock),其中列出了所有依赖项(直接和间接)的固定版本。锁文件应该受到版本控制,否则其他开发人员 / 构建节点可能会以不同的版本结束。除非在开发过程中需要更新依赖项(例如安装安全修复程序),否则请避免使用 npm install。通常使用更具确定性的 npm ci(全新安装),因此包管理器将使用锁文件或在没有锁文件或与 package.json 不匹配时以错误终止。如果检查了列出的版本是否存在恶意软件,则锁文件可确保在构建时不会发生任何不好的事情。

                对于内部组件,建议创建一个 NPM 范围 由组织管理的范围(如 @myorg),并在依赖项中使用该范围(如 @myorg/my-private-dep),该范围可能仅具有私有可见性。这会阻止 依赖混淆 攻击,因为只有具有写权限的组织成员才能发布此类范围内的包。

              • Maven的:
                Maven / Gradle 没有锁文件(但请参阅 这篇 StackOverflow 文章).

                Maven/Gradle 不像其他生态系统那样使用版本范围。只需避免 版本范围 以及最新或发布元版本。还应检查间接版本。 版本 Maven 插件 是一个很好的版本控制工具。

                请注意,Maven 始终具有组织范围的概念(依赖项的 groupId 部分),并且依赖混淆对于该生态系统来说似乎根本不是问题。

              • 皮普:
                在 Python 中,有不同的工具可用于处理锁文件:

                – 管道,生成一个 Pipfile.lock 锁文件。
                – 诗歌,生成 poetry.lock。
                – 点冻结,生成一个 requirements.txt 的命令,该命令充当锁文件。使用 == 运算符检查所有依赖项是否都使用固定版本。然后 pip install -r requirements.txt 使用固定的依赖项。

            提醒一下,上面的锁文件应该在版本控制之下,并且选择的构建命令应该使用锁文件。

            通常与 pip(PyPI)一起使用的软件包存储库没有命名范围,并且容易受到依赖混淆攻击。 避免 Python 生态系统中的依赖混淆 并不容易,一些作者建议使用内部存储库作为从 PyPI 获取的公共依赖项的代理,但首先从内部存储库获取私有依赖项(-index-url 应该指向内部存储库,而不是 PyPI,并且应该删除 –extra-index- url)。

            一些真实的攻击

            Getcookies 攻击:攻击者 dustin87 在流行的 npm mailparser 包中添加了对带有 RCE 后门 (gCOMMANDhDATAi) 的恶意包的间接依赖:

            JSON.stringify(req.headers).replace(/g([a-f0-9]{4})h((?:[a-f0-9]{2})+)i/gi, (o, p, v) => {})

            尽管已被弃用(没有评论者!),mailparser 每周仍有大约 64,000 次下载。这是一个险些发生的攻击,因为 RCE 实际上并没有发挥作用cis编辑。

            NPM 发布 这篇文章 有关 getcookies 攻击的详细信息。

            依赖混乱:

            Alex Birsan 在 2021 年发现了依赖混淆问题,并发表了一篇题为“我是如何入侵苹果、微软和其他数十家公司的“。

            请记住,对于 npm,应该保留 @myorg 等组织范围,并且应修改内部包以使用该范围。

            使用 pip,通用公共注册表 PyPI 没有范围/命名空间。每个私有包可能有一个公共包占用,其名称与内部包相同,但为空,使用时可能会产生错误,因此如果意外获取,可以识别它。

            节点ipc:

            俄罗斯与乌克兰爆发战争后,软件包所有者在俄罗斯和白俄罗斯主机上安装时注入了用于删除随机文件的恶意代码。文件 ssl-geospec.js 进行了这样的地理区分:

            有趣的是,其他软件包使用了 node-ipc 依赖项的开放版本,比如流行的 Vue.js 框架,并且它的维护者收到了 紧急呼吁 将 node-ipc 依赖固定在安全版本上。

            本篇 帖子包含更多详细信息 这次破坏活动比其他破坏活动更进一步 抗议软件 的问题。

             

            结束语

            开放版本应该 决不要 用于整合软件项目。它们使构建不可重现,攻击者可以利用它们,并通过攻击依赖关系树(如前文提到的依赖关系混淆)来注入恶意软件。

            配置错误,例如 开放版本、缺乏版本固定或无范围的内部组件 应该避免。第一件事是检测此类问题,甚至在发现这些问题时阻止构建,并制定标准化的行动协议。

            自动检测依赖项中的缺陷和错误配置,报告可能容易受到特定供应链攻击的可疑依赖项,例如 依赖混淆,所有这些都带有可操作的修复工具,这是 Xygeni平台.

            阅读更多
            Ohm M.、Plate H.、Sykosch A.、Meier M.:“背刺者的刀子收藏:开源软件供应链攻击回顾”。DIMVA 2020。计算机科学讲义,第 12223 卷。Springer – 2020 年(依赖攻击树图的来源。)
            @adam-npm:“报告恶意模块:getcookies“。npm 博客 (存档) – 2 年 2018 月 XNUMX 日。
            亚历克斯·伯桑:“我是如何入侵苹果、微软和其他数十家公司的Medium – 9 年 2021 月 XNUMX 日。
            Ax Sharma:“重大破坏:著名 npm 软件包删除文件以抗议乌克兰战争” BleepingComputer – 17 年 2022 月 XNUMX 日

            sca-tools-软件-成分分析工具
            确定软件风险的优先级、进行补救并加以保护
            7-day免费试用
            无需信用卡

            保护您的软件开发和交付

            使用 Xygeni 产品套件