即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

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

微信 前端外刊评论 31℃ 0评论
本文目录
[隐藏]

外刊君还在考虑在公司内做一些Node.js的尝试,正要撸起袖子写几行代码,就被这个漏洞给吓尿了,【漏洞分析】利用Node.js反序列化的漏洞执行远程代码(含演示视频) – 安全客 – 有思想的安全新媒体 关于Node.js存在反序列化远程代码执行漏洞的安全公告 Node.js惊爆重大漏洞。妈啊,这种惊天大漏洞,外刊君今年试点Node.js的kpi是不是完不成了?

1.这个漏洞是什么?

读了读上面这三篇文章,文中都提到了一个 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())')

2.这是 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自身的漏洞,更不是重大漏洞!

3.怎么修复这个漏洞?

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

Serialize a object including it’s function into a JSON

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

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

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

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

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

4.外刊君想说

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

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

转载请注明:CodingBlog » Node.js 这个反序列化的漏洞到底有多大?

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情
(5)个小伙伴在吐槽
  1. 所以用一个库之前,先去github看看主页再看看测试覆盖以及项目的lint配置,是很好的习惯
    Flashback2017-02-16 14:31 回复
  2. 看标题吓了一跳,原来是子虚乌有的事情
    被代码虐的渣渣2017-02-16 15:14 回复
  3. 真不知道 vm 是用来作甚的,Node.js 就不应该用 eval~~如果需要精确的知道输入的表达式,可以使用 Esprima 做语法树解析
    守望_小方_顺方-弟兄2017-02-16 15:18 回复
  4. PHP的反序列化现在还没补上
    hoosin2017-02-16 15:19 回复
  5. 引用作者在网上的回复,分享如何从根源避免这些漏洞: node-serialize 的作者李子骅:说回事情本身。如果要按照重要程度顺序列举每个开发者必须知道的安全准则,那么“不要相信来自用户的输入”一定会排在第一个。对于这个“漏洞”本身,其实抛开 eval 不说,根源是在于对用户输入可能引发的安全问题的忽视。这也是数据篡改、SQL 注入等安全问题的根本因素。node-serialize 允许将一段字符串反序列化成可执行的代码,其行为本身会将用户的恶意输入引来的安全问题放大。如果想要避免此类安全问题,需要解决的就是确保用户输入的安全。方法比如:1. 通过安全传输方式(内网 & 加密)传输序列化字符串;2. 使用如 RSA 等签名算法对字符串进行完整化校验。另外,要实现支持函数的可执行代码反序列化,就不得不用到 eval/new Function 这样平时编码不推荐使用的方法,这些方法比较容易引入安全问题,此时了解这些安全问题的根源是非常重要的。
    Tee Jay2017-02-17 01:01 回复