通过NPM生态系统中的依赖树揭开脆弱性传播及其演化的神秘面纱
本文实现了一个依赖约束解析器来解决NPM依赖约束的多样性,并在此基础上构建了一个完整的依赖漏洞知识图(DVGraph),以捕获所有NPM包之间的依赖关系。
https://www.secrss.com/articles/43424
https://zhuanlan.zhihu.com/p/594160921
https://sites.google.com/view/npm-vulnerability-study/
https://www.youtube.com/watch?v=CErMF3CgSc8
1. 背景介绍
NPM上发布了170多万个Node.js库,以促进软件开发。正如对比安全所揭示的,第三方库出现在当今软件的大多数(79%)中。然而,任何事物都有两面性。虽然使用库可以减少开发成本和时间,但这些集成库在实践中对软件生态系统构成了新的安全威胁,这些库中的漏洞可能会使依赖它们的软件不断面临安全风险。之前的工作已经调查了整个NPM生态系统的脆弱性影响,而他们的方法要么只是静态地考虑直接依赖性,或者基于依赖关系进行间接依赖的可达性分析,这可能会引入不准确的传递依赖关系,从而导致误报漏洞警告。现存的研究方法还没有提供一个精确的依赖关系。尤其是软件依赖关系之间的内部复杂关系,在很大程度上削弱了其分析的影响,并限制了进一步的解决方案(即精确修复)的提出。尽管一些现有的SCA工具(如Snyk和Blackduck)支持对用户项目进行NPM依赖性分析,但大多数工具都是从实际安装中检索依赖树,而不是从静态推理中检索依赖树。此外,由于语义版本控制的灵活性,依赖关系以及依赖关系中的漏洞实际上会随着时间的推移而发生动态变化。因此,尽管现有工作也调查了漏洞的影响,在没有静态和精确的依赖关系解决方案的情况下,大规模分析依赖关系中存在的漏洞传播的演变仍然是一个挑战,更不用说在防止漏洞动态引入依赖项方面获得实用的解决方案。
2. 论文主要成果
- 实现了一个依赖约束解析器来解决NPM依赖约束的多样性,并在此基础上构建了一个完整的依赖漏洞知识图(DVGraph),以捕获所有NPM包(超过114万个库和1094万个版本)之间的依赖关系,以及来自NVD的800多个已知CVE(常见漏洞和暴露),进一步的支持对漏洞传播的分析
- 提出了一种基于DVGraph的新算法(DTResolver),可以静态、精确地解析任意安装时间的依赖树,精度高达90%以上,并通过大约100k个代表性软件包进行了验证
- 进一步对依赖树中的脆弱性传播进行了实证研究。首先,我们研究了NPM依赖解析带来的依赖树的特征,在此基础上,我们分析了依赖树中漏洞传播的影响和特征,特别是传递依赖的漏洞。此外,我们还将研究扩展到时间维度,以研究依赖树中漏洞传播随时间的演变,揭示依赖树中引入漏洞的原因,以及可能的解决方案
3. 实验架构
包括依赖漏洞知识图构建、依赖树解析、漏洞路径识别及其验证、大规模实证研究以及对经验教训和解决方案的讨论,以及可能的研究方向
4. DVGraph的构建
为了支持高精度和高效率的大规模依赖漏洞分析,我们设计并实现了一套数据处理平台,以构建和维护完整而精确的依赖漏洞图DVGraph(基于neo4j)。
下图为改数据处理平台的框架:
**Metadata Pipeline:**将数据保存在元数据库中
**CVE Pipeline:**从NVD数据集收集CVE数据
**CVE Triage Pipeline:**手工标记CVE数据的对应的受影响的库和版本
**Graph Pipeline:**解析新来的元数据和映射的CVE数据,计算要在DVGraph上执行的操作(即添加、更改和删除节点和边),并最终执行这些操作
5. 依赖树解析和脆弱路径识别
5.1 依赖树解析
目前还没有一个考虑到特定于平台的依赖关系解决规则,可能导致不准确的依赖关系解析。本文目标是实现静态解析与NPM在实际安装过程中动态解析和安装的依赖树一致的依赖树,以便我们能够准确有效地识别依赖树中的漏洞和脆弱路径,而无需实际安装。
为了提高精度,同时保持效率,我们提出了一种基于DVGraph的依赖解析算法(DTResolver),可以在不安装的情况下,对任意数据软件包依赖解析的过程中,识别并找出所有依赖中含有安全漏洞的组件及相应的依赖引入路径
Dependency Tree Resolution
此外由于NPM中广泛使用依赖约束条件(版本范围)而不是固定版本进行依赖定义,导致依赖安装结果随着时间可能发生变化
如下图中,在B@1.0.1发布后,A@1.0.0的安装过程中,对B的依赖将解析成新发布的版本而不是原有的B@1.0.0, 图中C@1.0.1的发布亦是如此。因此我们在DTResolver的基础上进一步增加了时间约束,使其能够支持在给定项目从其发布前到DVGraph更新时间内任意时刻的依赖树模拟解析。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ybSfSOgB-1677142055487)(null)]
5.2 脆弱路径识别
给出了脆弱点和路径的示例 通过反向深度优先搜索(DFS)实现了一个脆弱路径提取器,以彻底查找依赖树中从脆弱点到根节点的依赖关系
### 5.3 评估验证
通过比较DTResolver解析的依赖树与实际安装的依赖树来验DTResolver。此外,我们将npm-remote-ls作为比较时的方法,这是一种广泛使用的公共API,在实践中无需实际安装即可获得依赖树,并且它完全遵循依赖范围来派生依赖树。
数据选择我们的验证基于两个标准收集的数据:(1)流行度,对于每个流行度指标(即过去、过去3年和去年下载量最多的明星、分叉、下载量多),我们分别选择了前2000个库。(2)中心性,对于每个中心性度量(即最大出入度),我们还选择了前2000个库和前20K个版本。分别地对于库,我们采用每个次要版本的最高补丁版本。最后,整理了15673个库中的103609个版本。
**DTResolver解析器的评估。**根据结果,90.58%的图树在忽略无法计算的情况(例如,具有捆绑的依赖项并且包含没有时间的依赖项)后与安装树完全匹配。而只有53.33%的远程树与安装树完全匹配,这是因为npm远程ls错过了一些官方的解决规则(例如,未弃用版本的优先级选择)。此外,我们进一步确定了不匹配依赖树的两个主要原因:1)在npm ls的输出中消除了依赖,这省略了一些包和依赖关系以简化树视图。2) 由于环境问题,依赖项可能无法完全安装(例如,当缺少所需的操作系统支持时,某些程序包可能无法安装)。此外,缺少库版本(即不在NPM注册表中或爬网失败)也会导致依赖关系树中缺少一些包。
**漏洞检测和漏洞路径识别评估。**除了DTResolver的评估,我们还扩展到比较检测到的漏洞和易受攻击的路径。由于从实际安装中检索到的安装树可能不完整(例如,依赖关系中的某些包由于环境问题而未安装),我们通过调用Graph Tree和Remote Tree中已识别的漏洞和漏洞路径来评估漏洞检测的准确性。我们发现DTResolver(98.1%)和npm远程ls(97.7%)在检测易受攻击组件方面具有相似的高覆盖率,但在识别易受攻击路径方面存在差异(92.60%对78.31%)。这可能是因为大多数依赖性约束都被解析为最满意的版本,并且依赖性范围也遵循这一规则,因此,仍然可以识别最脆弱的包。然而,通过依赖关系到达解决依赖关系忽略了NPM特定的解决规则,这会影响识别依赖关系路径的准确性。
6. 大规模实证研究
以下两个方面分析NPM中安全漏洞的影响:
- 漏洞如何影响NPM生态系统?漏洞如何通过依赖关系树传播影响根包(root packages)?
- 漏洞传播如何在依赖树中发展?依赖关系树的变化如何影响漏洞传播的演变?
6.1 通过依赖树传播漏洞
- 据统计证明,漏洞广泛存在于NPM包的依赖关系中(整个生态系统中有19.96%的库的四分之一版本)
- 第三方库的最新版本(16.17%)仍然存在通过依赖关系受到漏洞影响的潜在风险。
- 其他用户使用的易受攻击的库中,有相当一部分(超过100个)仍然有易受攻击的最新版本
- 一些有影响力的已知CVE广泛存在于大部分包的依赖树中
- 包通常受到多个漏洞的影响,每个漏洞通过多个漏洞路径影响根包(平均一个漏洞引入8个漏洞路径)
- 漏洞仍然广泛存在于受影响库版本的直接依赖关系中(超过30%),即使是最新版本
- 在易受攻击的路径上也存在中心性,即大多数易受攻击的路径都会通过有限的直接依赖关系,这可以用来切断易受攻击的路径
6.2 依赖树中的漏洞传播演化
- 随着时间的推移,已知的漏洞正在对NPM生态系统造成更大的影响。它们不仅影响到更多的库版本,而且还影响到依赖树中更脆弱的点
- 大多数CVE(93%)在被发现之前已经被引入依赖树,这些CVE的固定版本(87%)也大多在CVE发布之前发布
- 依赖树中只有60%的CVE被DTC自动删除,即使如此,每个CVE删除仍需要一年以上的时间
- 过时的维护(提供者)和不合适的依赖约束(使用者)是阻碍依赖树中漏洞自动移除的主要原因。应该采取更多的对策和解决方案来避免、监控甚至纠正这些不良做法
DTReme
添加了1)
前向漏洞检查
,在解析新的依赖关系的版本时(算法1中的第13行和第17行),只解析每个依赖关系的干净版本;2)
向后安装的包跟踪
,一旦没有干净版本可以解决,回滚到父节点的解析,并找到替代版本,以避免没有干净版本的情况。因此,我们可以彻底遍历所有可能的解决方案,找到可能的干净依赖树,并且可以为整个依赖树生成一个新的package-lock.json文件作为修复解决方案。
7、有限性
首先,依赖关系中的漏洞可能永远不会影响根包,因为可能永远无法访问这些易受攻击的功能。这只能通过基于依赖树和调用图分析易受攻击的函数调用路径来进一步解决。我们将此作为我们未来的工作。其次,CVE和库版本的映射是手动标记的,这可能会导致数据错误标记,合作的作者已将数据与现有CVE交叉验证,以缓解此类威胁。第三,我们无法区分包含缺失依赖项的安装,这可能会使基本事实不准确,我们只接受依赖项中成功安装的包作为验证中的基本事实。第四,由于计算成本过高,在分析漏洞传播时,我们忽略了具有超过1k条漏洞路径的版本。总的来说,这样的版本只占2.01%,这只能对我们的结果造成有限的偏差。
附录1 Npm依赖解析规则
https://docs.npmjs.com/cli/v9/commands/npm-install