节点socket.io,防止洪水?

我怎样才能防止某人干脆做

while(true){client.emit('i am spammer', true)}; 

当有人有冲动我的节点服务器的冲动,这肯定certificate是一个问题!

在这里输入图像描述

像tsrurzl说,你需要实施一个速率限制器 (节streamsockets)。

下面的代码示例只能在您的套接字返回一个Buffer(而不是一个string)时可靠地工作。 代码示例假定您将首先调用addRatingEntry(),然后立即调用evalRating()。 否则,在evalRating()根本没有被调用的情况下,您可能会发生内存泄漏。

 var rating, limit, interval; rating = []; // rating: [*{'timestamp', 'size'}] limit = 1048576; // limit: maximum number of bytes/characters. interval = 1000; // interval: interval in milliseconds. // Describes a rate limit of 1mb/s function addRatingEntry (size) { // Returns entry object. return rating[(rating.push({ 'timestamp': Date.now(), 'size': size }) - 1); } function evalRating () { // Removes outdated entries, computes combined size, and compares with limit variable. // Returns true if you're connection is NOT flooding, returns false if you need to disconnect. var i, newRating, totalSize; // totalSize in bytes in case of underlying Buffer value, in number of characters for strings. Actual byte size in case of strings might be variable => not reliable. newRating = []; for (i = rating.length - 1; i >= 0; i -= 1) { if ((Date.now() - rating[i].timestamp) < interval) { newRating.push(rating[i]); } } rating = newRating; totalSize = 0; for (i = newRating.length - 1; i >= 0; i -= 1) { totalSize += newRating[i].timestamp; } return (totalSize > limit ? false : true); } // Assume connection variable already exists and has a readable stream interface connection.on('data', function (chunk) { addRatingEntry(chunk.length); if (evalRating()) { // Continue processing chunk. } else { // Disconnect due to flooding. } }); 

您可以添加额外的检查,如检查尺寸参数是否真的是一个数字等。

附录:确保每个连接包含(在闭包中)等级,限制和间隔variables,并且不定义全局速率(每个连接操纵相同的等级)。

我实现了一个小洪水function,不完美(见下面的改进),但是当他做了很多请求时,它将断开用户。

 // Not more then 100 request in 10 seconds let FLOOD_TIME = 10000; let FLOOD_MAX = 100; let flood = { floods: {}, lastFloodClear: new Date(), protect: (io, socket) => { // Reset flood protection if( Math.abs( new Date() - flood.lastFloodClear) > FLOOD_TIME ){ flood.floods = {}; flood.lastFloodClear = new Date(); } flood.floods[socket.id] == undefined ? flood.floods[socket.id] = {} : flood.floods[socket.id]; flood.floods[socket.id].count == undefined ? flood.floods[socket.id].count = 0 : flood.floods[socket.id].count; flood.floods[socket.id].count++; //Disconnect the socket if he went over FLOOD_MAX in FLOOD_TIME if( flood.floods[socket.id].count > FLOOD_MAX){ console.log('FLOODPROTECTION ', socket.id) io.sockets.connected[socket.id].disconnect(); return false; } return true; } } exports = module.exports = flood; 

然后像这样使用它:

 let flood = require('../modules/flood') // ... init socket io... socket.on('message', function () { if(flood.protect(io, socket)){ //do stuff } }); 

改进就是,在计数旁添加另一个值,多less次他被隔离,然后创build一个禁止列表,不要让他连接了。 另外,当用户刷新页面,他得到一个新的socket.id所以也许在这里使用一个独特的cookie值,而不是socket.id