NestJS — Node.js للمؤسسات

تحديد معدل الطلبات والأمان والأداء

16 دقيقة الدرس 42 من 48

تحديد معدل الطلبات والأمان والأداء

يجب على تطبيق NestJS الإنتاجي أن يحمي نفسه من الإساءة، ويكشف ترويسات HTTP الأمنية الصحيحة، ويكون مضبوطًا لتحقيق أعلى إنتاجية. يتناول هذا الدرس أربعة محاور متكاملة: تحديد معدل الطلبات عبر @nestjs/throttler، وترويسات أمان HTTP باستخدام Helmet، وإعداد CORS، وضبط الأداء — بما يشمل محوّل Fastify وضغط الاستجابات وحدود حجم الحمولة.

تحديد معدل الطلبات مع @nestjs/throttler

تحجب وحدة throttler العملاء الذين يرسلون طلبات كثيرة جدًا في نافذة زمنية معيّنة، مما يحمي واجهتك البرمجية من هجمات القوة الغاشمة والاستهلاك الجامح.

npm install @nestjs/throttler

سجّل الوحدة بشكل عام وطبّق الحارس:

// app.module.ts import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler'; import { APP_GUARD } from '@nestjs/core'; @Module({ imports: [ ThrottlerModule.forRoot([ { ttl: 60_000, limit: 100 }, // 100 طلب كل 60 ثانية لكل IP ]), ], providers: [{ provide: APP_GUARD, useClass: ThrottlerGuard }], }) export class AppModule {}

تجاوَز الإعداد لكل مسار بمزيّن @Throttle()، أو استثنِ المسارات الداخلية بـ @SkipThrottle():

import { Throttle, SkipThrottle } from '@nestjs/throttler'; @Controller('auth') export class AuthController { @Throttle([{ ttl: 60_000, limit: 5 }]) // أشد: 5 محاولات تسجيل دخول/دقيقة @Post('login') login(@Body() dto: LoginDto) { /* ... */ } @SkipThrottle() @Get('health') health() { return { ok: true }; } }
خلفيات التخزين. يُخزّن throttler العدّادات في الذاكرة افتراضيًا — مقبول لنسخة واحدة. في النشر متعدد النسخ (موزّع على أجهزة متعددة)، انتقل إلى محوّل تخزين Redis (ThrottlerStorageRedisService من @nestjs/throttler-storage-redis) حتى تتشارك جميع النسخ العدّادات نفسها.

ترويسات أمان HTTP مع Helmet

تضبط Helmet مجموعة من ترويسات استجابة HTTP المعروفة التي تصلّب تطبيقك في مواجهة الهجمات الشائعة المستندة إلى المتصفح (XSS والنقر التدريجي وتخمين MIME وغيرها).

npm install helmet
// main.ts (محوّل Express — الافتراضي) import { NestFactory } from '@nestjs/core'; import helmet from 'helmet'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.use(helmet()); // يضبط X-Frame-Options وCSP وHSTS والمزيد await app.listen(3000); } bootstrap();
خصّص CSP بعناية. قد تكسر سياسة Content-Security-Policy الافتراضية لـ helmet() السكريبتات المدمجة أو موارد CDN الخارجية. مرّر كائن خيارات إلى helmet({ contentSecurityPolicy: { directives: { ... } } }) لتخصيصها، أو عطّل قاعدة CSP وحدها مع الإبقاء على البقية.

إعداد CORS

يجب تمكين CORS حتى تتمكّن عملاء المتصفح من استدعاء واجهتك البرمجية من أصل مختلف. يُغلّف NestJS حزمة cors:

// main.ts async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors({ origin: ['https://app.example.com', 'https://www.example.com'], methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], credentials: true, // السماح بالكوكيز / ترويسة Authorization maxAge: 86_400, // تخزين preflight مؤقت: 24 ساعة }); await app.listen(3000); } bootstrap();
لا تستخدم origin: '*' مع credentials: true أبدًا. ترفض المتصفحات هذه التوليفة. حدّد أصولًا بعينها، أو استخدم دالّة تحقّق ديناميكية تفحص قائمة السماح وتُعيد الأصل أو false.

الأداء: محوّل Fastify

يعتمد NestJS على Express افتراضيًا. يُضاعف استبدال Fastify الإنتاجية الخام عادةً لأن Fastify يمتلك محلّل HTTP أسرع ومحرك توجيه أكثر كفاءة.

npm install @nestjs/platform-fastify
// main.ts — محوّل Fastify import { NestFactory } from '@nestjs/core'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; async function bootstrap() { const app = await NestFactory.create<NestFastifyApplication>( AppModule, new FastifyAdapter({ logger: true }), ); await app.listen(3000, '0.0.0.0'); } bootstrap();
المقايضات. معظم كود NestJS محايد للمحوّل، لكن بعض الوسيط الخاص بـ Express (app.use(someExpressMiddleware)) لا يعمل مع Fastify. راجع قائمة وسيطك قبل التبديل.

الضغط وحدود الحمولة

يُقلّص تمكين ضغط gzip أحجام الاستجابات بشكل ملحوظ في واجهات JSON كثيفة. استخدم حزمة compression (Express) أو الإضافة المدمجة لـ Fastify:

// محوّل Express npm install compression npm install -D @types/compression // main.ts import * as compression from 'compression'; app.use(compression());

حدّد حجم جسم الطلب الوارد لمنع هجمات استنزاف الذاكرة. مع Express، اضبطه عند تسجيل محلّلي الجسم:

// main.ts — حد حجم الجسم (Express) const app = await NestFactory.create(AppModule, { bodyParser: false, // تعطيل الافتراضي للتخصيص }); import * as express from 'express'; app.use(express.json({ limit: '1mb' })); app.use(express.urlencoded({ extended: true, limit: '1mb' }));

الخلاصة

تجمع تطبيقات NestJS الآمنة عالية الأداء بين @nestjs/throttler لتحديد معدل الطلبات (حارس عام + تجاوزات لكل مسار)، وHelmet لترويسات الأمان، وCORS المُعدّ بقائمة أصول صريحة وcredentials: true عند الحاجة فقط، والمحوّل الاختياري Fastify لرفع الإنتاجية، والضغط لتقليص الاستجابات، وحدود حجم الجسم لمنع الإساءة. هذه ليست إضافات اختيارية — بل هي متطلبات أساسية لأي خدمة متاحة على الإنترنت.