如果我受到 DDOS 攻击,我正在尝试想出一种方法来帮助最大限度地减少对我的 node.js 应用程序的损害。我想限制每个 IP 的请求。我想将每个 IP 地址限制为每秒请求数。例如:任何 IP 地址每 3 秒不能超过 10 个请求。
到目前为止,我想出了这个:
http.createServer(req, res, function() {
if(req.connection.remoteAddress ?????? ) {
block ip for 15 mins
}
}
最佳答案
如果你想在应用程序服务器级别自己构建它,你将必须构建一个数据结构来记录来自特定 IP 地址的每个最近访问,以便当新请求到达时,你可以回顾历史并看看它是否一直在做太多的请求。如果是这样,请拒绝提供任何进一步的数据。而且,为了防止这些数据堆积在您的服务器中,您还需要某种清理代码来清除旧的访问数据。
这里有一个实现方法的想法(未经测试的代码来说明这个想法):
function AccessLogger(n, t, blockTime) {
this.qty = n;
this.time = t;
this.blockTime = blockTime;
this.requests = {};
// schedule cleanup on a regular interval (every 30 minutes)
this.interval = setInterval(this.age.bind(this), 30 * 60 * 1000);
}
AccessLogger.prototype = {
check: function(ip) {
var info, accessTimes, now, limit, cnt;
// add this access
this.add(ip);
// should always be an info here because we just added it
info = this.requests[ip];
accessTimes = info.accessTimes;
// calc time limits
now = Date.now();
limit = now - this.time;
// short circuit if already blocking this ip
if (info.blockUntil >= now) {
return false;
}
// short circuit an access that has not even had max qty accesses yet
if (accessTimes.length < this.qty) {
return true;
}
cnt = 0;
for (var i = accessTimes.length - 1; i >= 0; i--) {
if (accessTimes[i] > limit) {
++cnt;
} else {
// assumes cnts are in time order so no need to look any more
break;
}
}
if (cnt > this.qty) {
// block from now until now + this.blockTime
info.blockUntil = now + this.blockTime;
return false;
} else {
return true;
}
},
add: function(ip) {
var info = this.requests[ip];
if (!info) {
info = {accessTimes: [], blockUntil: 0};
this.requests[ip] = info;
}
// push this access time into the access array for this IP
info.accessTimes.push[Date.now()];
},
age: function() {
// clean up any accesses that have not been here within this.time and are not currently blocked
var ip, info, accessTimes, now = Date.now(), limit = now - this.time, index;
for (ip in this.requests) {
if (this.requests.hasOwnProperty(ip)) {
info = this.requests[ip];
accessTimes = info.accessTimes;
// if not currently blocking this one
if (info.blockUntil < now) {
// if newest access is older than time limit, then nuke the whole item
if (!accessTimes.length || accessTimes[accessTimes.length - 1] < limit) {
delete this.requests[ip];
} else {
// in case an ip is regularly visiting so its recent access is never old
// we must age out older access times to keep them from
// accumulating forever
if (accessTimes.length > (this.qty * 2) && accessTimes[0] < limit) {
index = 0;
for (var i = 1; i < accessTimes.length; i++) {
if (accessTimes[i] < limit) {
index = i;
} else {
break;
}
}
// remove index + 1 old access times from the front of the array
accessTimes.splice(0, index + 1);
}
}
}
}
}
}
};
var accesses = new AccessLogger(10, 3000, 15000);
// put this as one of the first middleware so it acts
// before other middleware spends time processing the request
app.use(function(req, res, next) {
if (!accesses.check(req.connection.remoteAddress)) {
// cancel the request here
res.end("No data for you!");
} else {
next();
}
});
此方法在 IP 地址监控方面也有常见的局限性。如果多个用户在 NAT 后共享一个 IP 地址,这会将他们全部视为一个用户,并且他们可能会因为他们的联合事件而被阻止,而不是因为一个用户的事件。
但是,正如其他人所说,当请求到达您的服务器这么远时,一些 DOS 损坏已经完成(它已经从您的服务器上占用了周期)。在执行更昂贵的操作(例如数据库操作)之前切断请求可能会有所帮助,但最好在更高级别(例如 Nginx 或防火墙或负载平衡器)检测并阻止它。
关于node.js - 如何在 Node.JS 中限制每个 ip 的请求量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26306863/