我怎樣才能防止有人簡單地做節點socket.io,防止氾濫的任何東西?
while(true){client.emit('i am spammer', true)};
這肯定被證明是一個問題,當有人衝動崩潰我的節點服務器!
我怎樣才能防止有人簡單地做節點socket.io,防止氾濫的任何東西?
while(true){client.emit('i am spammer', true)};
這肯定被證明是一個問題,當有人衝動崩潰我的節點服務器!
就像tsrurzl說你需要實現一個rate limiter(節流插座)。
以下代碼示例僅在您的套接字返回緩衝區(而不是字符串)時才能可靠地工作。代碼示例假定您將首先調用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.
}
});
您可以添加額外的檢查,如檢查尺寸參數是否真的是一個號碼等
附錄:確保等級,限制和時間間隔變量包含(在關閉)每個連接,並且它們沒有定義全局速率(每個連接操縱相同的評級)。
我實現了一個小洪水功能,並不完美(見下面的改進),但是當他做出很多請求時,它會斷開用戶的連接。
// 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
}
});
改進會是這樣,添加旁邊的計數,他得到了多久disconneted另一個值,然後創建一個banlist並且不要讓他接了。另外,當用戶刷新頁面時,他會得到一個新的socket.id,因此可能在此處使用一個唯一的cookie值而不是socket.id。
在接收到洪水後會終止連接(在短時間窗口中顯示一定數量的消息)可以接受嗎?當然,他們之後可以重新連接,但這會將問題轉變爲經典的DoS保護領域。 – zinga
http://stackoverflow.com/questions/16719749/how-can-i-prevent-malicious-use-of-my-sockets/20967971#20967971 – GiveMeAllYourCats
WebSockets,畢竟,只是插座。典型的通過防火牆的DoS保護可能就足夠了。你也可以實施類似節流套接字的東西,如果套接字仍然處於高流量狀態,那麼加班只會被丟棄。套接字具有會話關聯性,所以它實際上使得監視和限制套接字非常容易。 – tsturzl