NPM 蠕虫漏洞披露

  • Alex Blewitt
  • 顾俊

2016 年 4 月 13 日

话题:安全JavaScript语言 & 开发

NPM 项目已正式承认其存在一个长期的安全漏洞,该漏洞可能导致恶意的代码包可以在开发者系统上随意的运行任意代码,导致了第一个 NPM 创建的蠕虫。在一篇名为“npm 无法限制恶意代码包的行为”的漏洞说明 VU319816中,Sam Saccone 描述了创建一个蠕虫需要的步骤以及怎么让它自动传播。尽管这是在 2016 年一月被报道出来的,然而从 NPM 仓库管理初始版本发布开始,这个问题就已经存在而且被广泛知晓。

这个问题的根源在于,NPM 模块有相关的脚本文件,它们可以在安装的时候被 NPM 运行。当模块从 NPM 上被下载后,它有足够多的机会可以运行其代码:

  • preinstall - 在包被安装之前运行
  • postinstall - 在包被安装之后运行
  • preinstall - 在包被卸载之前运行
  • uninstall - 在包被卸载时运行
  • postuninstall - 在包被卸载之后运行

这些脚本使得 NPM 模块的发布更加简单并可以在使用之前进行内容的后期处理。举例来说,一些模块原本是由 CoffeeScript 或者 TypeScript 编写的,它们需要一个转化的步骤,或者是用 ES6 编写的,需要 Babel 转化后才能运行在目前的浏览器上。另外,JavaScript 库一般都会进行压缩(使其更小),这往往也是需要自动化运行的一个步骤。因为 JavaScript 是解释性的,像 make 这样的工具不会被使用,所以 npm 脚本就用来干这些苦力活。

在模块被客户端下载和使用的时候,NPM 错误地使用了这些代码,不光用来完成编译时间验证,还进行客户端运行。举例来说,left-pad惨状(InfoQ昨日报道)在重新发布模块后得到解决;然而,如果像这样被广泛使用的模块(例如true,其功能只是打印 true)有被影响的代码块,那么这样的代码运行在成千上万的机器上也有了可能。

这些代码满足了蠕虫的创建条件,然后这些蠕虫持续地影响其他的代码包并依次传播。NPM 包开发者使用标准的证书把他们的代码包(当然是通过 npm)发布到NPM 目录。为了加快发布,他们有可能会登录到该目录然后一直保持登录状态,此后任何的代码包都可以发布到该目录。正因如此,一旦一个 npm 包开发者的机器被攻占,蠕虫可以扫描其他的代码包,然后重新发布它们(通过开发者现有的证书),与此同时,蠕虫已经被注入到这些刚被感染的包的脚本代码块中。

甚至,包管理其自己也执行 JavaScript,这意味着仅仅是解决包的依赖就会导致任意代码的执行。这里有个例子可以最作为该概念的认证,一个代码包使用变量作为其包名,被发现可以伪装成任何的包。参考真实的开源精神,该概念认证是 MIT 证书认证:

A="$1"
    echo '{
       "name": "'"$A"'",
   "version": "2.0.0",
   "description": "",
   "main": "index.js",
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
   },
   "author": "",
   "license": "ISC"
}' > package.json
npm publish

如果一个包开发者下载了此代码包然后运行了其脚本,那么之后该包会运行 index.js,之后便可以在终端机器上运行任意的代码。该例子就展示了怎样运行 sudo rm -rf /,显然这会在没有任何备份的情况下造成严重后果。

NPM 目录允许任何人重新规划一个存在的代码包,只需要在他们的空间里用相同的命名发布一个新的版本,这使得该问题变得更加复杂。除非开发者特意的写死他们所依赖的代码包版本,否则很有可能自动更新到最近的版本并在之后遭受攻击。

到目前为止NPM 的回复都相当的软弱,否认了其对扫描恶意软件的责任,并指出开发者使用那些模块受到注入攻击也是咎由自取。然而整个基础都被设置成允许所有人拥有自己的包并可以用任何 JavaScript 替换这些包;尽管这些脚本可以被排除在外(通过使用 using npm install --ignore-scripts 或者 npm config set ignore-scripts true),然而还是有机会使用 require('shelljs').exec('rm -rf /') 替代 JavaScript 文件的内容,其运行时还是有着破坏性的影响。并且,让一个 npm 会话保持登录意味着任何应用,无论是基于 NodeJS 还是其他语言,都可以很容易的在用户不知晓的情况下以当前用户的名义发布脚本。

最近的这些事件表明,随着 JavaScript 的以及服务器端 NPM 使用的快速增长,其被赋予了和 JavaScript 语言本身一样的安全性的考虑。唯一让人感到惊讶的是,整个事件花费了这么长的时间才水落石出。

查看英文原文:NPM Worm Vulnerability Disclosed


感谢张龙对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。

安全JavaScript语言 & 开发