在远程存储库中使用排除模式的另一个案例:名称空间遮蔽(又名“依赖混淆”)攻击

使用JFrog Artifactory排除远程存储库中的模式,以避免名称空间阴影攻击

更新2021年6月1日。您要求,我们送货上门!更容易防止依赖混淆攻击!阅读更多-超越排除模式:具有优先级解决的安全存储库


博士TL;

npm注册表容易受到供应链命名空间阴影(也称为“依赖混淆”攻击)的攻击。确保你创建了npm作用域的包,并强制排除模式。

长期痴迷于排除模式

我记得我在2012年2月提供的第一次JFrog客户培训。在这张幻灯片上,我解释了在存储库中设置排除模式的重要性(你可以从幻灯片设计中看到这是2012年,对吧?而且,蚂蚁也是个东西。)

使用JFrog Artifactory的常见配置包括和排除模式

故事是这样的:你的公司Acme安装了JFrog Artifactory。它有一组常用的远程存储库(代理各种中央存储库,如Maven central)、本地存储库(托管您公司的内部构件)和虚拟存储库(在单个URL下聚合本地和远程存储库),简化了构建工具的配置(在2012年,这将是Maven,对吧)。

想象一下,我说,你正在研究一个非常秘密的项目,叫做“秘密阿尔莫”。工件坐标是org.acme: secret-almo: 1.0你不想让你的竞争对手知道这件事。但如果你的同事不小心加了org.acme: secret-almo: 1.1作为此库的依赖项或任何不存在的版本,并运行构建?这是将要发生的事情:

  1. 请求到达Artifactory的虚拟存储库,这(一如既往)检查局部存储库第一个。如果您的同事没有犯错误并使用1.0作为版本,那么解析就会停止,并检索到正确的工件。但是1.1没有找到,所以Artifactory继续寻找。
  2. Artifactory查看远程存储库,它们是虚拟仓库的一部分,一个接一个地将包含您的秘密项目名称的URL请求发送到外部第三方存储库!

“不行! !”我叫道。“多么可怕的忽视隐私啊!”如果有人看到请求,发现了秘密阿尔莫怎么办!?!”这是一种激励用户使用排除模式的合适方式。真的有那么严重的危险吗?我对此表示怀疑,但确实有所帮助。

自2009年以来,我们一直在向我们的客户和用户灌输这样的信息:2015年,Ariel Seftel- - - - - -”在远程存储库上定义一个排除模式,以防止Artifactory通过它们搜索您知道其中不存在的包,”又是2015年的Shani Levy——这次是专门针对安全问题:”通过排除模式管理安全性并获得性能提升再一次,拉米·霍宁在2016年说道- - - - - -”修改…排除模式以强制执行安全策略。"

最古老的用户指南是Artifactory 2,由联合创始人约阿夫·兰德曼和弗雷德·西蒙于2009年撰写,你猜怎么着?就在这里

它是对存储库使用包含和排除模式很重要。这对于远程存储库尤其重要,以便:

  1. 避免在存储库中查找永远不会包含这些工件的远程工件,或者只包含有限范围的组id。
  2. 不向任何可以拦截查询的人(包括远程存储库本身的所有者)透露可能从工件查询中获得的敏感业务信息。

很明显,当前的文档也强调一下:

为远程存储库使用排除模式以避免安全风险的最佳实践

为避免暴露上述敏感业务信息,我们强烈建议采用以下最佳实践:

  • 组织中使用的远程存储库列表应该在一个虚拟存储库下进行管理,所有请求都指向该虚拟存储库
  • 文件中指定所有内部构件排除模式使用通配符来封装尽可能广泛的内部构件规范的虚拟存储库(或者每个远程存储库)的字段。

好吧,你明白了;我们是在排除模式。但是为什么呢?这真的是因为我们害怕Sonatype (Maven Central的维护者)或GitHub (npm Registry的维护者)中的人会仔细检查日志并发现Secret Almo吗?是的,但不仅如此。进入完美风暴…

Caret, Bazaar和Virtual Repository

让我们回到Acme的办公室(现在可能是虚拟的),Secret Almo的工作仍在进行中。让我们来看看这个项目的另一个组成部分,一点也不秘密,也许是一个图书馆,almo-common-utils。它的源代码甚至可以公开访问,例如,如果它是作为Acme的公开访问的产品或web应用程序的一部分,它是用Node和JFrog Artifactory编写的,现在有一组远程(代理官方的npm注册表)、本地(用于内部共享模块)和虚拟nphth华体会最新官方网站m存储库。

考虑以下几点:

  1. npm Registry是一个Bazaar (用雷蒙德的话来说).任何人可以发布一个未限定作用域的NPM库并调用它吗不管他们想要什么,即。almo-common-utils(除非有名字冲突)。
  2. 没有名为“almo-common-utils的注册表(好吧,因为它是一个内部公司库),所以没有名称冲突。
  3. 声明的大多数npm依赖项都使用范围(波浪号或插入号)请求最新兼容版本,如语义版本控制标准和它的NPM实施

攻击者试图攻击未受保护的组织所需要的唯一信息是almo-common-utils使用的库的主要版本(假设他们知道在组织中广泛使用版本3),以及源代码的内容。

他们可以克隆和修改源代码,将任何恶意软件嵌入其中,但仍然保持与原始代码的兼容性,并将其上传到npm Registrysecret-almo: 3.99.99因为谁能阻止他们呢?

现在让我们看看人工分辨率是如何工作的没有排除模式secret-almo: ^ 3.0.0请求:

  1. 在本地存储库中查找最新的兼容秘密算法。发现第3.2.4。
  2. 在npm-registry代理远程存储库中查找最新兼容的秘密算法。发现3.99.99。
  3. 来自npm注册表的伪秘密almo胜出,而供应链被劫持

还记得我喊“不!”吗?这是双重否定。哎呦。

但这是一个经验丰富的Node.js开发人员会站起来说…

但是有作用域的包!

还记得我告诉过你任何人都可以上传任何东西到npm注册表吗?嗯,不完全是。如果你在npm注册表中创建了一个组织,你会被分配一个命名空间,只有你的组织成员才能上传(这就是npm调用的名称)公共作用域包).它能使您免受命名空间阴影攻击吗?是的,如果做得好。

首先,公司必须创建组织并保留命名空间,因为就像npm Registry中的所有东西一样,它们都是可以争夺的。如果你的组织没有保留它,更复杂的攻击仍然可能成功——现在攻击者不得不希望一些没有经验的开发人员能在npm Registry中找到一个具有熟悉作用域的包(“嘿,看,有一个@acme / almo-common-utils在这里,它肯定是我们的”),并决定使用它。此外,即使是官方组织的成员也可能被忽视,发布未限定作用域的包。

解决方案吗?你现在知道了……

两个简单的规则可以让你免受命名空间阴影(又名“依赖混淆”)的攻击

  1. 只发布有作用域的包!在npm Registry中为你的公司注册一个正式的组织。始终只发布公共作用域的包。顺便说一句,它还简化了排除模式(参见下一条规则),因为您只需要排除.npm / @acme / *现在要排除在远程存储库中搜索的所有包。
  2. 在远程存储库上使用排除模式!你知道这是事实almo-common-utils永远不会在npm注册表中找到?告诉您的存储库管理员!在排除模式中添加私有依赖项并保护自己免受严重(而且相当聪明)的供应链攻击。这太容易了,不这样做几乎是被忽视了。

我们最后讲……

《你的魔鬼代言人》常见问题解答

问:只有当我使用Artifactory时,命名空间阴影(又名“依赖混淆”)攻击才会造成安全问题吗?

答:任何允许在单个URL下组合本地和代理存储库的存储库管理器都可以以类似的方式受到攻击。所以,这不是人工制造的安全问题。这些产品包括Sonatype Nexus等。这并不是因为它们都在某种程度上存在缺陷——它们完全按照预期工作。他们都有并且强烈推荐使用类似于排除模式的最佳实践(例如Sonatype Nexus中的路由规则)。

问:为什么人们不使用公共作用域的包?这不是该走的路吗?

A:这是一条正确的道路。但是npm只在版本2中引入了有作用域的包,它在业界并不像它应该的那样普遍(至少到目前为止)。但是你呢?你很酷,所以你会用它们,对吧?

问:为什么npm Registry不强制由经过验证的所有者限定包的作用域,以避免命名空间跟踪攻击?

A:这是一个非常好的问题。