我试图想办法帮助减少我的node.js应用程序受到的损害,如果我得到DDOS攻击的话。我想限制每个IP的请求。我想将每个IP地址限制为每秒这么多请求。例如:没有IP地址每3秒钟可以超过10个请求。
到目前为止,我已经想出了这个:
http.createServer(req, res, function() {
if(req.connection.remoteAddress ?????? ) {
block ip for 15 mins
}
}
答案 0 :(得分:4)
如果您想在应用服务器级别自行构建,则必须构建一个数据结构,记录来自特定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或防火墙或负载均衡器)检测和阻止此操作会更好。
答案 1 :(得分:2)
我认为这不应该在http服务器级别完成。基本上,它不会阻止用户访问您的服务器,即使他们在15分钟内看不到任何内容。
在我看来,你应该使用防火墙在你的系统中处理它。虽然这更像是ServerFault或SuperUser的讨论,但请允许我给您一些指示。
使用 iptables 在您的入口点设置防火墙(您的服务器或您有权访问该线路的其他任何内容)。 iptables允许您设置每个IP的最大连接数限制。如果您没有网络背景,那么学习曲线非常陡峭。这是传统的方式。
这是一个面向初学者的好资源:Iptables for beginners
类似于您需要的内容:Unix StackExchange
我最近遇到了一个名为Uncomplicated Firewall (ufw)的非常好的软件包,它碰巧有一个限制每个IP连接速率的选项,并在几分钟内完成设置。对于更复杂的东西,你仍然需要iptables。
总之,像Brad所说,
让您的应用程序服务器执行他们最擅长的操作...运行您的应用程序。
让防火墙做他们最擅长的事情,从服务器中取出不需要的IP。
答案 2 :(得分:1)
如果您使用Nodejs过滤连接或应用连接策略,那就不好了。
最好在NodeJS前面使用Nginx
客户 - &gt; Nginx - &gt; Nodejs或Application。
这并不困难和便宜,因为Ngnix太开源了。
祝你好运。答案 3 :(得分:1)
我们可以使用npm Package
npm i limiting-middleware
代码:
const LimitingMiddleware = require('limiting-middleware');
app.use(new LimitingMiddleware({ limit: 100, resetInterval: 1200000 }).limitByIp());
// 100 request limit. 1200000ms reset interval (20m).
有关更多信息:Click here