From 4336d8941d9f79c68e4673fda09717c6d836e141 Mon Sep 17 00:00:00 2001 From: Lukasz niemkiewicz Date: Tue, 4 Oct 2022 10:06:32 +0200 Subject: [PATCH 1/3] docs(docs.nestjs.com) show example of enabling Throttle rate limiting behind proxies with express the documentation was unsufficient to succesfuly implement the throttling since the external link to express suggested using 'app.set' method, wich by default throws 'property set does not exist` error --- .swp | Bin 0 -> 12288 bytes content/security/rate-limiting.md | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 .swp diff --git a/.swp b/.swp new file mode 100644 index 0000000000000000000000000000000000000000..2cab0a0dc2524e21d670623d88491f5894f84db4 GIT binary patch literal 12288 zcmeI%u};G<5C&iu#DEw;@B#-6U1(KW26zMpB!(7NT<6kQP2a^U=Ed z@jABt#q|^c0uX=z1Rwwb2tWV=5P$##AOL{_6wsMcXXi={($)O`-+cdnrTP0Ne}L!0 zmLUKE2tWV=5P$##AOHafKmY<;1xOt6qV^mDg*a)~-qq}7Nr8nj$AKy*v?a|88{~u7 zd*{{PLK6SO%~%ST-4V^LDQLW;jB_1JA(Fzoc_1YPr@ki6xDqYa zRW#RuVijVZTVqqU*>Z@+aL8l1Bs;51ZdRufyecD7HeFL|((AppModule); + app.set('trust proxy', 'loopback') // specify a single subnet + await app.listen(3000) +} +bootstrap(); +``` + +Doing so will allow you to get the original IP address from the `X-Forwarded-For` header, and you can override the `getTracker()` method to pull the value from the header rather than from `req.ip`. The following example works with both express and fastify: ```typescript // throttler-behind-proxy.guard.ts From a1a767edd2235d28e94dd335a5f992a46548f1b4 Mon Sep 17 00:00:00 2001 From: Kamil Mysliwiec Date: Fri, 18 Oct 2024 12:56:03 +0200 Subject: [PATCH 2/3] Update content/security/rate-limiting.md Co-authored-by: Jackie McDoniel --- content/security/rate-limiting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/security/rate-limiting.md b/content/security/rate-limiting.md index 57548dc5d7..1fad9116d4 100644 --- a/content/security/rate-limiting.md +++ b/content/security/rate-limiting.md @@ -73,7 +73,7 @@ findAll() { #### Proxies If your application runs behind a proxy server, check the specific HTTP adapter options ([express](http://expressjs.com/en/guide/behind-proxies.html) and [fastify](https://www.fastify.io/docs/latest/Reference/Server/#trustproxy)) for the `trust proxy` option and enable it. -Following example enables `trust proxy` for express adapter: +The following example enables `trust proxy` for the `express` adapter: ```typescript //main.ts From a2aa4e81816c6447a78c2251b82976068e217005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20My=C5=9Bliwiec?= Date: Fri, 18 Oct 2024 12:59:07 +0200 Subject: [PATCH 3/3] chore: improve wording --- .swp | Bin 12288 -> 0 bytes content/security/rate-limiting.md | 57 +++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 16 deletions(-) delete mode 100644 .swp diff --git a/.swp b/.swp deleted file mode 100644 index 2cab0a0dc2524e21d670623d88491f5894f84db4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI%u};G<5C&iu#DEw;@B#-6U1(KW26zMpB!(7NT<6kQP2a^U=Ed z@jABt#q|^c0uX=z1Rwwb2tWV=5P$##AOL{_6wsMcXXi={($)O`-+cdnrTP0Ne}L!0 zmLUKE2tWV=5P$##AOHafKmY<;1xOt6qV^mDg*a)~-qq}7Nr8nj$AKy*v?a|88{~u7 zd*{{PLK6SO%~%ST-4V^LDQLW;jB_1JA(Fzoc_1YPr@ki6xDqYa zRW#RuVijVZTVqqU*>Z@+aL8l1Bs;51ZdRufyecD7HeFL|((AppModule); - app.set('trust proxy', 'loopback') // specify a single subnet - await app.listen(3000) + app.set('trust proxy', 'loopback'); // Trust requests from the loopback address + await app.listen(3000); } + +bootstrap(); +@@switch +import { NestFactory } from '@nestjs/core'; +import { AppModule } from './app.module'; +import { NestExpressApplication } from '@nestjs/platform-express'; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + app.set('trust proxy', 'loopback'); // Trust requests from the loopback address + await app.listen(3000); +} + bootstrap(); ``` -Doing so will allow you to get the original IP address from the `X-Forwarded-For` header, and you can override the `getTracker()` method to pull the value from the header rather than from `req.ip`. The following example works with both express and fastify: +Enabling `trust proxy` allows you to retrieve the original IP address from the `X-Forwarded-For` header. You can also customize the behavior of your application by overriding the `getTracker()` method to extract the IP address from this header instead of relying on `req.ip`. The following example demonstrates how to achieve this for both Express and Fastify: ```typescript -// throttler-behind-proxy.guard.ts +@@filename(throttler-behind-proxy.guard) import { ThrottlerGuard } from '@nestjs/throttler'; import { Injectable } from '@nestjs/common'; @@ -132,11 +147,6 @@ export class ThrottlerBehindProxyGuard extends ThrottlerGuard { return req.ips.length ? req.ips[0] : req.ip; // individualize IP extraction to meet your own needs } } - -// app.controller.ts -import { ThrottlerBehindProxyGuard } from './throttler-behind-proxy.guard'; - -@UseGuards(ThrottlerBehindProxyGuard) ``` > info **Hint** You can find the API of the `req` Request object for express [here](https://expressjs.com/en/api.html#req.ips) and for fastify [here](https://www.fastify.io/docs/latest/Reference/Request/). @@ -149,15 +159,30 @@ This module can work with websockets, but it requires some class extension. You @Injectable() export class WsThrottlerGuard extends ThrottlerGuard { async handleRequest(requestProps: ThrottlerRequest): Promise { - const { context, limit, ttl, throttler, blockDuration, getTracker, generateKey } = requestProps; + const { + context, + limit, + ttl, + throttler, + blockDuration, + getTracker, + generateKey, + } = requestProps; const client = context.switchToWs().getClient(); const tracker = client._socket.remoteAddress; const key = generateKey(context, tracker, throttler.name); const { totalHits, timeToExpire, isBlocked, timeToBlockExpire } = - await this.storageService.increment(key, ttl, limit, blockDuration, throttler.name); + await this.storageService.increment( + key, + ttl, + limit, + blockDuration, + throttler.name, + ); - const getThrottlerSuffix = (name: string) => (name === 'default' ? '' : `-${name}`); + const getThrottlerSuffix = (name: string) => + name === 'default' ? '' : `-${name}`; // Throw an error when the user reached their limit. if (isBlocked) {