So'rovlar tezligini cheklash
Ilovalarni brute-force hujumlardan himoyalashning keng tarqalgan usuli - rate-limiting. Boshlash uchun @nestjs/throttler paketini o'rnatishingiz kerak.
Ilovalarni brute-force hujumlardan himoyalashning keng tarqalgan usuli - rate-limiting. Boshlash uchun @nestjs/throttler paketini o'rnatishingiz kerak.
1$ npm i --save @nestjs/throttlerO'rnatish tugagach, ThrottlerModule ni boshqa Nest paketlari kabi forRoot yoki forRootAsync metodlari bilan sozlashingiz mumkin.
1@Module({
2 imports: [
3 ThrottlerModule.forRoot({
4 throttlers: [
5 {
6 ttl: 60000,
7 limit: 10,
8 },
9 ],
10 }),
11 ],
12})
13export class AppModule {}Yuqoridagi sozlama ttl (millisekundlarda yashash vaqti) va limit (ttl ichidagi maksimal so'rovlar soni) bo'yicha global opsiyalarni belgilaydi; ular guard bilan himoyalangan ilova routelarida qo'llanadi.
Modul import qilingach, ThrottlerGuard ni qanday bog'lashni tanlashingiz mumkin. guards bo'limida aytilgan har qanday bog'lash turi mos keladi. Masalan, guardni global bog'lamoqchi bo'lsangiz, quyidagi providerni istalgan modulga qo'shishingiz mumkin:
1{
2 provide: APP_GUARD,
3 useClass: ThrottlerGuard
4}Bir nechta Throttler ta'riflari
Ba'zi holatlarda bir nechta throttling ta'riflarini sozlamoqchi bo'lishingiz mumkin, masalan soniyada 3 tadan ortiq bo'lmasin, 10 soniyada 20 tadan ortiq bo'lmasin va bir daqiqada 100 tadan ortiq bo'lmasin. Buni amalga oshirish uchun ta'riflaringizni nomlangan opsiyalar bilan massivga joylashingiz mumkin, keyinchalik esa @SkipThrottle() va @Throttle() dekoratorlarida bu nomlarga murojaat qilib opsiyalarni yana o'zgartirasiz.
1@Module({
2 imports: [
3 ThrottlerModule.forRoot([
4 {
5 name: 'short',
6 ttl: 1000,
7 limit: 3,
8 },
9 {
10 name: 'medium',
11 ttl: 10000,
12 limit: 20
13 },
14 {
15 name: 'long',
16 ttl: 60000,
17 limit: 100
18 }
19 ]),
20 ],
21})
22export class AppModule {}Moslashtirish
Ba'zan guardni controllerga yoki global darajada bog'lab, lekin bir yoki bir nechta endpointlar uchun rate limitingni o'chirmoqchi bo'lishingiz mumkin. Buning uchun @SkipThrottle() dekoratoridan foydalanib, butun klass yoki bitta routening throttlerini inkor qilasiz. @SkipThrottle() dekoratori string kalitlari va boolean qiymatlaridan iborat obyektni ham qabul qilishi mumkin; bu controllerning aksariyat qismini istisno qilib, hammasini emas, va bir nechta throttler bo'lsa, ularni alohida sozlash uchun kerak bo'ladi. Agar obyekt bermasangiz, default qiymat {{ '{' }} default: true {{ '}' }} bo'ladi.
1@SkipThrottle()
2@Controller('users')
3export class UsersController {}Bu @SkipThrottle() dekoratori route yoki klassni o'tkazib yuborish, yoki klass bo'ylab skip qilingan route ichidagi aniq routeda skipni bekor qilish uchun ishlatiladi.
1@SkipThrottle()
2@Controller('users')
3export class UsersController {
4 // Rate limiting is applied to this route.
5 @SkipThrottle({ default: false })
6 dontSkip() {
7 return 'List users work with Rate limiting.';
8 }
9 // This route will skip rate limiting.
10 doSkip() {
11 return 'List users work without Rate limiting.';
12 }
13}Shuningdek, global modulda o'rnatilgan limit va ttl ni qattiqroq yoki yumshoqroq qilish uchun @Throttle() dekoratoridan foydalanishingiz mumkin. Bu dekorator klassda ham, funksiyada ham ishlatiladi. 5-versiyadan boshlab dekorator throttler to'plami nomiga mos string va limit/ttl kalitlariga ega integer qiymatli obyektni qabul qiladi, xuddi root modulga uzatiladigan opsiyalar kabi. Agar original opsiyalarda nom berilmagan bo'lsa, default stringidan foydalaning. Uni quyidagicha sozlashingiz kerak:
1// Override default configuration for Rate limiting and duration.
2@Throttle({ default: { limit: 3, ttl: 60000 } })
3@Get()
4findAll() {
5 return "List users works with custom rate limiting.";
6}Proksilar
Agar ilovangiz proksi server ortida ishlayotgan bo'lsa, HTTP adapterda proksiga ishonishni sozlash muhim. trust proxy sozlamasini yoqish uchun Express va Fastify uchun mos HTTP adapter opsiyalariga qarang.
Quyida Express adapteri uchun trust proxy ni yoqish misoli keltirilgan:
1import { NestFactory } from '@nestjs/core';
2import { AppModule } from './app.module';
3import { NestExpressApplication } from '@nestjs/platform-express';
4
5async function bootstrap() {
6 const app = await NestFactory.create<NestExpressApplication>(AppModule);
7 app.set('trust proxy', 'loopback'); // Trust requests from the loopback address
8 await app.listen(3000);
9}
10
11bootstrap();trust proxyni yoqish X-Forwarded-For headeridan asl IP manzilni olish imkonini beradi. Shuningdek, req.ip ga tayanmasdan, ushbu headerdan IP manzilni ajratib olish uchun getTracker() metodini override qilib ilova xatti-harakatini sozlashingiz mumkin. Quyidagi misol buni Express va Fastify uchun qanday qilishni ko'rsatadi:
1import { ThrottlerGuard } from '@nestjs/throttler';
2import { Injectable } from '@nestjs/common';
3
4@Injectable()
5export class ThrottlerBehindProxyGuard extends ThrottlerGuard {
6 protected async getTracker(req: Record<string, any>): Promise<string> {
7 return req.ips.length ? req.ips[0] : req.ip; // individualize IP extraction to meet your own needs
8 }
9}Express uchun req Request obyektining API sini bu yerda va fastify uchun bu yerda topishingiz mumkin.
Websockets
Bu modul websockets bilan ishlashi mumkin, ammo buning uchun klassni kengaytirish kerak. ThrottlerGuard ni kengaytirib, handleRequest metodini quyidagicha override qilishingiz mumkin:
1@Injectable()
2export class WsThrottlerGuard extends ThrottlerGuard {
3 async handleRequest(requestProps: ThrottlerRequest): Promise<boolean> {
4 const {
5 context,
6 limit,
7 ttl,
8 throttler,
9 blockDuration,
10 getTracker,
11 generateKey,
12 } = requestProps;
13
14 const client = context.switchToWs().getClient();
15 const tracker = client._socket.remoteAddress;
16 const key = generateKey(context, tracker, throttler.name);
17 const { totalHits, timeToExpire, isBlocked, timeToBlockExpire } =
18 await this.storageService.increment(
19 key,
20 ttl,
21 limit,
22 blockDuration,
23 throttler.name,
24 );
25
26 const getThrottlerSuffix = (name: string) =>
27 name === 'default' ? '' : `-${name}`;
28
29 // Throw an error when the user reached their limit.
30 if (isBlocked) {
31 await this.throwThrottlingException(context, {
32 limit,
33 ttl,
34 key,
35 tracker,
36 totalHits,
37 timeToExpire,
38 isBlocked,
39 timeToBlockExpire,
40 });
41 }
42
43 return true;
44 }
45}Agar ws dan foydalanayotgan bo'lsangiz, _socket o'rniga conn dan foydalanish kerak
WebSockets bilan ishlaganda e'tiborga olish kerak bo'lgan bir nechta narsa bor:
- Guardni
APP_GUARDyokiapp.useGlobalGuards()bilan ro'yxatdan o'tkazib bo'lmaydi - Limitga yetilganda, Nest
exceptioneventini chiqaradi, shuning uchun bu uchun listener tayyor bo'lishi kerak
Agar @nestjs/platform-ws paketidan foydalansangiz, client._socket.remoteAddress o'rniga ishlatishingiz mumkin.
GraphQL
ThrottlerGuard GraphQL so'rovlari bilan ishlash uchun ham qo'llanilishi mumkin. Yana, guardni kengaytirish mumkin, lekin bu safar getRequestResponse metodi override qilinadi.
1@Injectable()
2export class GqlThrottlerGuard extends ThrottlerGuard {
3 getRequestResponse(context: ExecutionContext) {
4 const gqlCtx = GqlExecutionContext.create(context);
5 const ctx = gqlCtx.getContext();
6 return { req: ctx.req, res: ctx.res };
7 }
8}Konfiguratsiya
Quyidagi opsiyalar ThrottlerModule opsiyalarining massiviga uzatiladigan obyekt uchun yaroqli:
name | qaysi throttler to'plami ishlatilayotganini ichki kuzatish uchun nom. Berilmasa default default |
ttl | har bir so'rov storage'da qancha millisekund saqlanishi |
limit | TTL limitida maksimal so'rovlar soni |
blockDuration | so'rov qancha millisekund bloklanishi |
ignoreUserAgents | so'rovlarni throttle qilishda e'tibordan chetda qoldiriladigan user-agent regexlari massivi |
skipIf | ExecutionContext ni qabul qilib, throttler mantiqini short circuit qiladigan boolean qaytaruvchi funksiya. @SkipThrottler() ga o'xshaydi, lekin so'rovga asoslanadi |
Agar storage sozlamoqchi bo'lsangiz yoki yuqoridagi opsiyalarning ayrimlarini har bir throttler to'plamiga globalroq qo'llamoqchi bo'lsangiz, throttlers opsiyasi orqali yuqoridagi opsiyalarni berib, quyidagi jadvaldan foydalanishingiz mumkin.
storage | throttling qayerda kuzatilishi uchun custom storage xizmati. Bu yerga qarang. |
ignoreUserAgents | so'rovlarni throttle qilishda e'tibordan chetda qoldiriladigan user-agent regexlari massivi |
skipIf | ExecutionContext ni qabul qilib, throttler mantiqini short circuit qiladigan boolean qaytaruvchi funksiya. @SkipThrottler() ga o'xshaydi, lekin so'rovga asoslanadi |
throttlers | yuqoridagi jadvaldan foydalanib aniqlangan throttler to'plamlari massivi |
errorMessage | string YOKI ExecutionContext va ThrottlerLimitDetail ni qabul qilib, default throttler xato xabarini override qiladigan string qaytaruvchi funksiya |
getTracker | Request ni qabul qilib, `getTracker` metodining default mantiqini override qiladigan string qaytaruvchi funksiya |
generateKey | ExecutionContext, tacker string va throttler nomi string ni qabul qilib, rate limit qiymatini saqlash uchun ishlatiladigan yakuniy kalitni override qiladigan string qaytaruvchi funksiya. Bu `generateKey` metodining default mantiqini override qiladi |
Async konfiguratsiya
Rate-limiting konfiguratsiyasini sinxron emas, asinxron tarzda olishni xohlashingiz mumkin. Bunda forRootAsync() metodidan foydalanishingiz mumkin, u dependency injection va async metodlarni qo'llab-quvvatlaydi.
Usullardan biri - factory funksiyasidan foydalanish:
1@Module({
2 imports: [
3 ThrottlerModule.forRootAsync({
4 imports: [ConfigModule],
5 inject: [ConfigService],
6 useFactory: (config: ConfigService) => [
7 {
8 ttl: config.get('THROTTLE_TTL'),
9 limit: config.get('THROTTLE_LIMIT'),
10 },
11 ],
12 }),
13 ],
14})
15export class AppModule {}useClass sintaksisidan ham foydalanishingiz mumkin:
1@Module({
2 imports: [
3 ThrottlerModule.forRootAsync({
4 imports: [ConfigModule],
5 useClass: ThrottlerConfigService,
6 }),
7 ],
8})
9export class AppModule {}Bu ThrottlerConfigService ThrottlerOptionsFactory interfeysini implementatsiya qilsa bo'ladi.
Storage
Ichki storage - bu global opsiyalarda belgilangan TTL o'tguncha yuborilgan so'rovlarni kuzatib turadigan xotiradagi (in-memory) kesh. ThrottlerStorage interfeysini implementatsiya qiladigan klass bo'lsa, ThrottlerModule ning storage opsiyasiga o'zingizning storage variantingizni ulashingiz mumkin.
Taqsimlangan serverlar uchun yagona truth manbai sifatida Redis uchun hamjamiyat storage providerdan foydalanishingiz mumkin.
ThrottlerStorage@nestjs/throttler paketidan import qilinadi.
Time helpers
Vaqtlarni o'qilishi osonroq qilish uchun bir nechta yordamchi metodlar mavjud. @nestjs/throttler beshta yordamchini eksport qiladi: seconds, minutes, hours, days, va weeks. Ulardan foydalanish uchun seconds(5) yoki boshqa helperlardan birini chaqirish kifoya, shunda to'g'ri millisekund qiymati qaytariladi.
Migratsiya qo'llanmasi
Ko'pchilik uchun opsiyalarni massivga o'rashning o'zi yetarli bo'ladi.
Agar custom storage ishlatayotgan bo'lsangiz, ttl va limit ni massivga o'rab, opsiyalar obyektidagi throttlers xossasiga tayinlang.
@SkipThrottle() dekoratorlaridan har qanday biri muayyan route yoki metodlar uchun throttlingni aylanib o'tish uchun ishlatilishi mumkin. U ixtiyoriy boolean parametrini qabul qiladi va default true bo'ladi. Bu muayyan endpointlarda rate limitingni o'tkazib yuborish kerak bo'lganda foydali.
@Throttle() dekoratorlari endi string kalitli obyektni qabul qilishi kerak, bu kalitlar throttler kontekstlarining nomlariga mos keladi (nom bo'lmasa yana 'default') va qiymatlar limit va ttl kalitlariga ega obyektlar bo'ladi.
ttl endi millisekundlarda. Agar o'qilish uchun ttlni soniyalarda saqlamoqchi bo'lsangiz, ushbu paketning seconds helperidan foydalaning. U ttlni 1000 ga ko'paytirib, millisekundga aylantiradi.
Batafsil ma'lumot uchun Changelogga qarang.