fix(core): Use rate limiter for task runner endpoints (#12486)

This commit is contained in:
Tomi Turtiainen 2025-01-08 10:06:36 +02:00 committed by GitHub
parent b1d17f5201
commit 491cb605e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 0 deletions

View file

@ -2,6 +2,7 @@ import { GlobalConfig } from '@n8n/config';
import { Service } from '@n8n/di'; import { Service } from '@n8n/di';
import compression from 'compression'; import compression from 'compression';
import express from 'express'; import express from 'express';
import { rateLimit as expressRateLimit } from 'express-rate-limit';
import { Logger } from 'n8n-core'; import { Logger } from 'n8n-core';
import * as a from 'node:assert/strict'; import * as a from 'node:assert/strict';
import { randomBytes } from 'node:crypto'; import { randomBytes } from 'node:crypto';
@ -147,8 +148,16 @@ export class TaskRunnerServer {
} }
private configureRoutes() { private configureRoutes() {
const createRateLimiter = () =>
expressRateLimit({
windowMs: 1000,
limit: 5,
message: { message: 'Too many requests' },
});
this.app.use( this.app.use(
this.upgradeEndpoint, this.upgradeEndpoint,
createRateLimiter(),
// eslint-disable-next-line @typescript-eslint/unbound-method // eslint-disable-next-line @typescript-eslint/unbound-method
this.taskRunnerAuthController.authMiddleware, this.taskRunnerAuthController.authMiddleware,
(req: TaskRunnerServerInitRequest, res: TaskRunnerServerInitResponse) => (req: TaskRunnerServerInitRequest, res: TaskRunnerServerInitResponse) =>
@ -158,6 +167,7 @@ export class TaskRunnerServer {
const authEndpoint = `${this.getEndpointBasePath()}/auth`; const authEndpoint = `${this.getEndpointBasePath()}/auth`;
this.app.post( this.app.post(
authEndpoint, authEndpoint,
createRateLimiter(),
send(async (req) => await this.taskRunnerAuthController.createGrantToken(req)), send(async (req) => await this.taskRunnerAuthController.createGrantToken(req)),
); );

View file

@ -19,4 +19,26 @@ describe('TaskRunnerServer', () => {
await agent.get('/healthz').expect(200); await agent.get('/healthz').expect(200);
}); });
}); });
describe('/runners/_ws', () => {
it('should return 429 when too many requests are made', async () => {
await agent.post('/runners/_ws').send({}).expect(401);
await agent.post('/runners/_ws').send({}).expect(401);
await agent.post('/runners/_ws').send({}).expect(401);
await agent.post('/runners/_ws').send({}).expect(401);
await agent.post('/runners/_ws').send({}).expect(401);
await agent.post('/runners/_ws').send({}).expect(429);
});
});
describe('/runners/auth', () => {
it('should return 429 when too many requests are made', async () => {
await agent.post('/runners/auth').send({ token: 'invalid' }).expect(403);
await agent.post('/runners/auth').send({ token: 'invalid' }).expect(403);
await agent.post('/runners/auth').send({ token: 'invalid' }).expect(403);
await agent.post('/runners/auth').send({ token: 'invalid' }).expect(403);
await agent.post('/runners/auth').send({ token: 'invalid' }).expect(403);
await agent.post('/runners/auth').send({ token: 'invalid' }).expect(429);
});
});
}); });