如何限制我的 http 服务器上的 /socket.io 路由?
How can I rate limit the /socket.io route on my http server?
我正在使用 socket.io 并使用 rate-limiter-flexible and limiter 来限制请求率,但我注意到路由 /socket.io 没有从任何一个接收到 429,事实上,我可以'使用 app.use('/socket.io')..
记录来自此路由的任何请求
我认为 socket.io 正在对这条路线进行一些底层处理,对吗?如果是这样,我如何确保对 /socket.io 的请求在达到限制后也收到 429?
Connect 上的速率限制器:
this.io.on(this.SocketConstants.CONNECTION, async (client) => {
this.client = client;
try {
await this.rateLimiter.consume(client.handshake.address);
} catch (rejRes) {
// On flood
client.error('Too many requests');
client.disconnect(true);
}
http 服务器上的速率限制器:
class RateLimiting {
constructor() {
this.limiter = new RateLimiter(2, 'minute', true);
this.index = this.index.bind(this);
}
index(req,res,next){
try {
this.limiter.removeTokens(1, function(err, remainingRequests) {
if (remainingRequests < 1) {
res.writeHead(429, {'Content-Type': 'text/plain;charset=UTF-8'});
res.end('429 Too Many Requests - your IP is being rate limited');
// res.status(429).json({ message: 'Too many requests' });
} else {
next();
}
});
}
catch(err){
console.log('Error', err);
}
}
}
编辑
对于遇到类似问题的任何人,我最终尝试了几种不同的方法来完成此任务,其中最简单的方法是:
- 编写自己的 allowRequest
AllowRequest 是一个 pass/fail 函数,您可以使用它来覆盖默认的 "checkRequest" 函数 (reference here)
checkBucket(err, remainingRequests) {
remainingRequests < 1 ? false : true;
}
allowRequest(req, callback) {
const limit = this.limiter.removeTokens(1, this.checkBucket);
callback(limit ? null : 'Too many requests', limit);
}
并且服务器启动为
this.io = this.socketServer(server,
{
allowRequest: this.allowRequest
});
- 选择不同的路由,使用 express 添加所需的任何中间件并禁用默认路由
您可以通过将 serveClient
设置为 false 并将 path
设置为您需要的任何值来完成此操作。
this.io = this.socketServer(服务器,
{
路径:'/newSocketRoute',
服务客户端:假
});
这对我来说不太适用,所以我提供套接字文件的方式可能有问题,但它看起来像这样:
app.get("/socket", this.limiter.initialize(), function(req, res) {
if (0 === req.url.indexOf('/newSocketRoute/socket.io.js.map')) {
res.sendFile(join(__dirname, "../../node_modules/socket.io-client/dist/socket.io.js.map"));
} else if (0 === req.url.indexOf('/newSocketRoute/socket.io.js')) {
res.sendFile(join(__dirname, "../../node_modules/socket.io-client/dist/socket.io.js"));
}
});
Socket.io 通过将自己作为第一个侦听器插入到 request
事件(socket.io 代码 reference here)来附加到您的 http 服务器,这意味着它完全绕过任何Express 中间件。
如果您尝试对 /socket.io/socket.io.js
(客户端 socket.io 代码)的请求进行速率限制,那么您可以使用自己的自定义路由器在 Express 中为该文件创建自己的路由使用不同的路径,让您的客户端只使用路径的 Express 版本,然后您可以通过 socket.io 禁用该文件(有一个禁用它的选项)。
如果您尝试对传入 socket.io 连接进行速率限制,那么您可能需要修改速率限制器,以便它可以参与 socket.io 连接事件。
现在我想到了,您可以像 socket.io 那样破解 request
事件侦听器列表(您可以查看上面引用的代码 link 了解它是如何做到的) 并且您可以在它看到请求之前插入您自己的速率限制。 socket.io 正在做的是实现一个穷人的中间件并切到线路的最前面,这样他们就可以首先破解任何传入的 http 请求,如果他们已经处理了它,就对其他人隐藏起来。你可以对你的速率限制器做同样的事情。然后,您将参加 "arm's race" 比赛,看看谁先得手。就个人而言,如果违反速率限制规则,我可能只是挂钩 connect
事件并终止那里的连接。但是,您可以破解并获得 socket.io 代码。
我正在使用 socket.io 并使用 rate-limiter-flexible and limiter 来限制请求率,但我注意到路由 /socket.io 没有从任何一个接收到 429,事实上,我可以'使用 app.use('/socket.io')..
我认为 socket.io 正在对这条路线进行一些底层处理,对吗?如果是这样,我如何确保对 /socket.io 的请求在达到限制后也收到 429?
Connect 上的速率限制器:
this.io.on(this.SocketConstants.CONNECTION, async (client) => {
this.client = client;
try {
await this.rateLimiter.consume(client.handshake.address);
} catch (rejRes) {
// On flood
client.error('Too many requests');
client.disconnect(true);
}
http 服务器上的速率限制器:
class RateLimiting {
constructor() {
this.limiter = new RateLimiter(2, 'minute', true);
this.index = this.index.bind(this);
}
index(req,res,next){
try {
this.limiter.removeTokens(1, function(err, remainingRequests) {
if (remainingRequests < 1) {
res.writeHead(429, {'Content-Type': 'text/plain;charset=UTF-8'});
res.end('429 Too Many Requests - your IP is being rate limited');
// res.status(429).json({ message: 'Too many requests' });
} else {
next();
}
});
}
catch(err){
console.log('Error', err);
}
}
}
编辑
对于遇到类似问题的任何人,我最终尝试了几种不同的方法来完成此任务,其中最简单的方法是:
- 编写自己的 allowRequest
AllowRequest 是一个 pass/fail 函数,您可以使用它来覆盖默认的 "checkRequest" 函数 (reference here)
checkBucket(err, remainingRequests) {
remainingRequests < 1 ? false : true;
}
allowRequest(req, callback) {
const limit = this.limiter.removeTokens(1, this.checkBucket);
callback(limit ? null : 'Too many requests', limit);
}
并且服务器启动为
this.io = this.socketServer(server,
{
allowRequest: this.allowRequest
});
- 选择不同的路由,使用 express 添加所需的任何中间件并禁用默认路由
您可以通过将 serveClient
设置为 false 并将 path
设置为您需要的任何值来完成此操作。
this.io = this.socketServer(服务器, { 路径:'/newSocketRoute', 服务客户端:假 });
这对我来说不太适用,所以我提供套接字文件的方式可能有问题,但它看起来像这样:
app.get("/socket", this.limiter.initialize(), function(req, res) {
if (0 === req.url.indexOf('/newSocketRoute/socket.io.js.map')) {
res.sendFile(join(__dirname, "../../node_modules/socket.io-client/dist/socket.io.js.map"));
} else if (0 === req.url.indexOf('/newSocketRoute/socket.io.js')) {
res.sendFile(join(__dirname, "../../node_modules/socket.io-client/dist/socket.io.js"));
}
});
Socket.io 通过将自己作为第一个侦听器插入到 request
事件(socket.io 代码 reference here)来附加到您的 http 服务器,这意味着它完全绕过任何Express 中间件。
如果您尝试对 /socket.io/socket.io.js
(客户端 socket.io 代码)的请求进行速率限制,那么您可以使用自己的自定义路由器在 Express 中为该文件创建自己的路由使用不同的路径,让您的客户端只使用路径的 Express 版本,然后您可以通过 socket.io 禁用该文件(有一个禁用它的选项)。
如果您尝试对传入 socket.io 连接进行速率限制,那么您可能需要修改速率限制器,以便它可以参与 socket.io 连接事件。
现在我想到了,您可以像 socket.io 那样破解 request
事件侦听器列表(您可以查看上面引用的代码 link 了解它是如何做到的) 并且您可以在它看到请求之前插入您自己的速率限制。 socket.io 正在做的是实现一个穷人的中间件并切到线路的最前面,这样他们就可以首先破解任何传入的 http 请求,如果他们已经处理了它,就对其他人隐藏起来。你可以对你的速率限制器做同样的事情。然后,您将参加 "arm's race" 比赛,看看谁先得手。就个人而言,如果违反速率限制规则,我可能只是挂钩 connect
事件并终止那里的连接。但是,您可以破解并获得 socket.io 代码。