Node.js 这个反序列化的漏洞到底有多大?

Posted 前端外刊评论

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js 这个反序列化的漏洞到底有多大?相关的知识,希望对你有一定的参考价值。

外刊君还在考虑在公司内做一些Node.js的尝试,正要撸起袖子写几行代码,就被这个漏洞给吓尿了, 。妈啊,这种惊天大漏洞,外刊君今年试点Node.js的kpi是不是完不成了?

这个漏洞是什么?

读了读上面这三篇文章,文中都提到了一个 node-serialize 的 Node.js 库。这个库提供的 API unserialize 函数提供了注入的可能:

 
   
   
 
  1. var serialize = require('node-serialize');

  2. var payload = '{"rce":"_$$ND_FUNC$$_function(){require(\'child_process\').exec(\'ls /\',function(error, stdout, stderr) { console.log(stdout)});}()"}';

  3. serialize.unserialize(payload);

unserialize 内部有这么一段代码(简单起见,我稍微加工了一下):

 
   
   
 
  1. if (obj[key].indexOf('_$$ND_FUNC$$_') === 0) {

  2.  obj[key] = eval('(' + obj[key].substring('_$$ND_FUNC$$_'.length) + ')');

  3. }

我们简化一下,

 
   
   
 
  1. eval('(function(){require(\'child_process\').exec(\'ls /\',function(error, stdout, stderr) { console.log(stdout)});}()"})')

简化一下例子,如果用户输入 {"rce":"_$$ND_FUNC$$_process.exit()"},就能把服务器给停掉。

 
   
   
 
  1. eval('(process.exit())')

这是 Node.js 的重大漏洞吗?

看看国家安全漏洞共享平台是怎么说的:

根据漏洞研究者测试结果,由于涉及IIFE函数表达式,漏洞影响到Node.js现有的所有版本。根据CNVD秘书处的普查结果,目前互联网上直接标定使用node.js运行环境的服务器约有6.8万余台,其中排名前五名的国家和地区是美国(占比58.9%)、中国(23.2%)、英国(4.1%)、荷兰(3.6%)、德国(3.0%)。由于一个应用广泛的名为Express的WEB应用开发框架是基于node.js运行环境的,根据CNVD秘书处初步普查结果,受该漏洞影响的网站服务器有可能超过70万台,后续CNVD将进一步进行漏洞实际威胁影响的精确评估,做好境内用户的应急响应工作。

本段的说法有几点有待商磋。

由于涉及IIFE函数表达式,漏洞影响到Node.js现有的所有版本:这个漏洞处在 eval 函数而不是 IIFE;本文的开头已经给出了对应CVE(通用漏洞列表)的链接 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3087:

Apache Struts 2.3.20.x before 2.3.20.3, 2.3.24.x before 2.3.24.3, and 2.3.28.x before 2.3.28.1, when Dynamic Method Invocation is enabled, allow remote attackers to execute arbitrary code via vectors related to an ! (exclamation mark) operator to the REST Plugin.

例子是 Apache Struts 的,攻击者可以远程通过动态调用来实现攻击。这与 eval 的问题是异曲同工的。

由于一个应用广泛的名为Express的WEB应用开发框架是基于node.js运行环境的,根据CNVD秘书处初步普查结果,受该漏洞影响的网站服务器有可能超过70万台:node-serialize 包的有问题,就推导出 Node.js 有问题,然后再说使用 Express 的这70万台服务器有问题,这似乎没有道理。

狭隘地说,这个漏洞只是类库 node-serialize 在使用 eval 这种 javascript 社区不推荐使用的函数造成的。这不是 Node.js 的漏洞,因为问题并不是出现在 Node.js 的源码中。

影响有多大呢?外刊君去看了这个项目在github上的star是20,在npmjs.org上可以看到有几个类库依赖它,但这些依赖它的类库每个月下载量甚至是个位数。因此影响超过70万台的说法完全是无中生有嘛。

往广里说,这其实是 JavaScript 自身的问题。JavaScript 提供了 eval 函数,对一段字符串形式的 JavaScript 代码进行求值。但是:

Don't use eval needlessly!eval() is a dangerous function, which executes the code it's passed with the privileges of the caller. If you run eval() with a string that could be affected by a malicious party, you may end up running malicious code on the user's machine with the permissions of your webpage / extension. More importantly, third party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways to which the similar Function is not susceptible.——https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/eval

其实在 JavaScript 中已经非常不倡导使用 eval 了。

总之,这不是Node.js自身的漏洞,更不是重大漏洞!

怎么修复这个漏洞?

针对 node-serialize,这个漏洞无法从源码上修复。这个库的目标是:

Serialize a object including it's function into a JSON

将一个对象序列化成 JSON 字符串,包括这个对象上的函数。也就是在反序列化时,必须将字符串函数通过 eval 或者 newFunction() 转成函数。实现这个库的目标,必须使用这种不安全的方式,因此无论 node-serialize 怎么处理对传入的字符串进行检查,都会留下不安全的隐患。

因此,库的作者给出了两条建议:

  • 在封闭的内部环境中使用这个库,将它们与潜在的注入者完全隔离;比如只从后端服务器传递序列化的对象给前端服务器,并且使用 HTTPs 代替 HTTP;

  • 通过非对称加密(RSA)加密序列化数据,避免被篡改。

在外刊君看来,唯一修复或者避免这个漏洞的方法,就是不再使用 node-serialize 这个库,不再使用 eval 之类可以给注入者带来无限可能的 JavaScript 糟粕,尤其是在后端代码中。

外刊君想说

文前开头的三篇文章的作者,搞安全研究能不能长点心,别老是想搞个大新闻。这漏洞的影响范围真的是放卫星了。可以看看国外最开始提出这个漏洞的文章https://opsecx.com/index.php/2017/02/08/exploiting-node-js-deserialization-bug-for-remote-code-execution/,国内的示例代码,截图都和这篇文章一样,翻译能不能注明出处?还可以看看原文下面的评论,读者 Lukas 已经指出原文的问题——标题党、过分夸大,搞不清楚问题在哪里。

eval 不能用,eval 不能用,eval 不能用,重要的事情说三遍。当然, newFunction 也不能用,这是一个无限的坑。可以使用比如 ESLint 这样的工具来进行检查。


以上是关于Node.js 这个反序列化的漏洞到底有多大?的主要内容,如果未能解决你的问题,请参考以下文章

利用 Node.js 反序列化漏洞远程执行代码

Node.js惊爆重大漏洞

技术讨论 | 记一次Node.Js反序列化攻击测试

什么是 Kraken.js 套装,它对 Node.js 的安全性和可扩展性有多大帮助?

GET和POST可传递的值到底有多大

基操勿 6 | Node.js 的异步I/O到底有多秀?