这个故事开始于基于 React 的开源文档项目 Docusaurus 的维护者 Sébastien Lorber 注意到对包清单的 Pull Request 更改。以下是对流行的 cliui npm 包的建议更改:
具体来说,让我们注意使用不熟悉的语法的 npm 依赖项更改:
"dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
大多数开发人员希望在包或 Git 或基于文件的 URL 的值中看到 semver 版本范围。然而,在这种情况下,有一个特殊的 npm: 前缀语法。是什么意思?
因此,在此拉取请求中提出的更改的情况下,包 string-width-cjs 将解析为版本 ^4.2.0 中的包 string-width。这意味着将有一个 string-width-cjs 的 node_modules 目录条目,但包含 string-width@^4.2.0 的内容以及锁定文件 (package-lock.json) 中的类似行为。
包别名是 npm 包管理器的一项功能,可以合法地用于此处暗示的情况(以帮助 ESM 与 CJS 支持)。
话虽如此,包别名可能会被滥用。在一篇可追溯到 2021 年的文章和安全披露中,Snyk 大使 Nishant Jain 演示了如何欺骗官方 npmjs 注册表,基于包别名错误地提供依赖信息,作为依赖混淆和供应链安全问题的一部分。
这个拉取请求确实是良性的,并且不存在供应链攻击的风险。 然而,Sébastien 对这样的包名产生了怀疑,并发现还有更多值得担心的事情。
当Sébastien检查拉取请求时,他运行了一个名为lockfile-lint的工具,该工具有助于验证锁文件,例如package-lock.json或yarn.lock,以确保它们不会被篡改以注入恶意包,而不是原始的 npm 包。
运行该工具显示以下警告:
npx lockfile-lint --path package-lock.json --allowed-hosts yarn npm --validate-https --validate-package-names detected resolved URL for package with a different name: string-width-cjs expected: string-width-cjs actual: string-width detected resolved URL for package with a different name: strip-ansi-cjs expected: strip-ansi-cjs actual: strip-ansi detected resolved URL for package with a different name: wrap-ansi-cjs expected: wrap-ansi-cjs actual: wrap-ansi ✖ Error: security issues detected!
免责声明:lockfile-lint 是我在 2019 年开发的一个工具,该工具披露了锁文件的安全问题: 为什么 npm lockfiles 可能成为注入恶意模块的安全盲点.
鉴于上述 lockfile-lint 结果,Sébastien 在 npm 上查找了这些包名称,并惊讶地发现它们确实存在于公共 npm 注册表中:
Sébastien 指出,这些包名称不仅存在于 npm 上,而且它们还具有引起关注的指标:
查看 npm 包 strip-ansi-cjs,没有自述文件,也没有与该包关联的源代码存储库,但有许多合法且流行的包引用了相同的行为。
事实上,对于这个特定的软件包,有许多依赖项(依赖于此软件包的其他软件包)形式的受欢迎程度信号 - 确切地说,有 529 个依赖项,并且每周下载量也在不断增加,总计 7,274 次写作时。
查看 strip-ansi-cjs 的代码,它显示该包中只有一个文件,即包清单 package.json 文件。
那么,为什么一个不做任何事情的包会获得如此多的下载,以及为什么还有那么多其他包依赖它?
让我们继续考察这些npm包的作者。
这三个软件包均属于himanshutester002,它们的软件包均于去年发布,并带有程序化版本号。有些很有趣:
You can also note that the user himanshutester002 has no identifiable information on this user profile page on npmjs.
We previously noted that the strip-ansi-cjs npm package has over 500 other packages that use it, therefore, potentially a positive indicator for popularity. Let’s look at them:
If you give it a glance, this might transfer some sort of legitimacy with this list, but is it?
For example, names like clazz-transformer or react-native-multiply or maybe gh-monoproject-cli seem legitimate, but are they?
Here is the react-native-multiply npm package page:
This package has virtually no downloads and its author is also an anonymous npm user with no identifiable information. The source URL repository this package redirects to is https://github[.]com/hasandader/react-native-multiply which doesn’t exist and the GitHub user profile looks very suspicious and lacks practical activity.
The npm package contents might seem like there’s some actual source code in there, but in reality, it looks like a generated code sample for a “hello world” application prototype.
You also have to wonder, if this package is just a multiplication library, then why does it need 776 dependencies to do the following:
import { multiply } from 'react-native-multiply'; const result = await multiply(3, 7);
While some may mock JavaScript for its abuse of dependencies, contributing to an astronomical tree of nested packages, it doesn’t make any sense for a project to declare 776 direct (top-level) dependencies.
Among all of these dependencies, are the 3 suspicious npm packages that our story began with: string-width-cjs, strip-ansi-cjs, and wrap-ansi-cjs:
We mentioned that one of the strip-ansi-cjs dependencies was named clazz-transformer. Let’s look at it:
Let’s explain what is happening here:
The associated repository’s typstack/class-transformer on GitHub has the package.json file as follows:
Looking at the package.json file on GitHub shows no declaration of dependencies, yet if we inspect the source code of the actual package on npmjs we see the 437 dependencies that this clazz-transformer is packaged with. Again, very conveniently bundling the 3 suspicious *-cjs packages:
Before we draw further conclusions, it is important to mention a few of the traits of the npm packages we observed above:
我们在 Sonatype 的同行之前已经发现过类似的软件包淹没开源注册表的案例。在这些情况下,开发人员的最终目标是用 Tea 代币奖励自己,这是一个用于通过开源软件货币化的 Web3 平台。
在上述包中找到一些 tea.yaml 文件进一步支持了这一论点,即该活动的部分目的是通过滥用 Tea 来挖掘 Tea 代币。
今年早些时候,2024 年 4 月 14 日,一位茶论坛用户发表了一条评论,进一步支持了对茶滥用的担忧:
在给出结论之前,我要真诚地感谢 Sébastien Lorber 谨慎的维护者心态,并帮助揭示潜在的 npm 供应链攻击的线索。
此时,我非常有信心可以继续在其余据称依赖于 string-width-cjs 的包中找出漏洞,以找到非常可疑的真实合法性指标。
我的假设是,所有这些依赖包和下载量增加的唯一目的是为 3 个 *-cjs 包创建虚假合法性,以便在适当的时候,在适当的受害者参与的情况下,这些假包将安装,然后使用新的恶意版本。
为了帮助您在使用开源软件时保持安全,我强烈建议采用安全实践,特别是以下后续教育资源:
我们是否在他们的不法行为中发现了供应链安全活动,或者这一切都与金钱轨迹有关,因此可以归因于垃圾邮件和滥用 npm 和 GitHub 等公共注册中心来挖掘 Tea 代币?
无论如何,请保持警惕。
以上是可疑的维护者揭露了 npm 供应链攻击的线索的详细内容。更多信息请关注PHP中文网其他相关文章!