דלג לתוכן הראשי

שומרים ואינטרספטורים של אבטחה

מערכת BT Management משתמשת במספר Guards ו-Interceptors גלובליים כדי לאכוף אבטחה, אימות והרשאות בכל בקשה ל-API.

סדר ביצוע השומרים (Guards Execution Order)

כל בקשת HTTP עוברת דרך השומרים הבאים לפי הסדר:

1. JwtAuthGuard

תפקיד: אימות אסימון (JWT Token).

  • מה הוא עושה:
    • מחלץ את ה-Bearer Token מכותרת ה-Authorization.
    • מאמת את חתימת האסימון באמצעות JWT_SECRET.
    • מפענח את ה-Payload ומזרים את user ל-request.user.
  • דילוג:
    • אם הנקודת הקצה (Endpoint) מסומנת עם @Public(), השומר מדולג.
  • מיקום הקוד: src/auth/guards/jwt-auth.guard.ts

2. PermissionsGuard

תפקיד: בדיקת הרשאות משתמש.

  • מה הוא עושה:
    • קורא את הדקורטור @Permissions() מנקודת הקצה.
    • בודק אם למשתמש יש את ההרשאות הנדרשות (request.user.permissions).
    • מאפשר גישה אוטומטית למשתמשים עם isAdmin: true.
  • דילוג:
    • אם הנקודת הקצה ציבורית (@Public()).
    • אם אין דקורטור @Permissions() (מניח שאין דרישה).
  • מיקום הקוד: src/common/guards/permissions.guard.ts

3. RateLimitGuard

תפקיד: הגנה מפני התקפות DoS ושימוש יתר.

  • מה הוא עושה:
    • מגביל את מספר הבקשות למשתמש או כתובת IP בפרק זמן מסוים.
    • משתמש ב-Redis לשמירת מונים.
    • מחזיר 429 Too Many Requests אם חרגו מהגבול.
  • הגדרה:
    • ברירת מחדל: 100 בקשות לדקה למשתמש.
    • ניתן להתאמה אישית לפי נקודת קצה באמצעות @RateLimit() decorator.
  • מיקום הקוד: src/common/guards/rate-limit.guard.ts

4. AccountLockoutGuard

תפקיד: נעילת חשבונות לאחר ניסיונות התחברות כושלים.

  • מה הוא עושה:
    • בודק אם החשבון נעול (user.isLocked: true).
    • מחזיר 403 Forbidden אם החשבון נעול.
    • המערכת נועלת חשבון אוטומטית לאחר 5 ניסיונות כושלים.
  • שחרור נעילה:
    • אוטומטי לאחר 30 דקות.
    • ידני על ידי מנהל מערכת.
  • מיקום הקוד: src/common/guards/account-lockout.guard.ts

סכימת זרימה

Client Request

[JwtAuthGuard] ← אימות אסימון

[PermissionsGuard] ← בדיקת הרשאות

[RateLimitGuard] ← הגבלת קצב

[AccountLockoutGuard] ← בדיקת נעילה

[TenantInterceptor] ← הגדרת הקשר דייר (ALS)

Controller Method ← קריאה למתודה

[TransformInterceptor] ← עיטוף תגובה

Client Response

אינטרספטורים (Interceptors)

אינטרספטורים רצים לאחר השומרים ולפני/אחרי המתודה של הקונטרולר.

TenantInterceptor

תפקיד: הגדרת הקשר דייר (Tenant Context) באמצעות ALS.

  • מה הוא עושה:
    • מחלץ את userId מתוך request.user.
    • בודק אם יש כותרת x-customer-context (התחזות מנהל).
    • מגדיר את ה-Store של AlsService עם { userId, isAdmin }.
  • חשיבות:
    • זה הבסיס למערכת Multi-Tenancy.
    • כל שאילתות Prisma מסתמכות על זה לסינון אוטומטי.
  • מיקום הקוד: src/common/interceptors/tenant.interceptor.ts

TransformInterceptor

תפקיד: עיטוף תגובות במבנה אחיד.

  • מה הוא עושה:
    • עוטף כל תגובה בפורמט:
      {
      "success": true,
      "data": { ... },
      "count": 10
      }
    • מוסיף count אם התוצאה היא מערך.
  • דילוג:
    • אם הנקודת הקצה מסומנת עם @PlainResponse() (למשל: הורדת קבצים).
  • מיקום הקוד: src/common/interceptors/transform.interceptor.ts

דקורטורים מותאמים אישית

@Public()

שימוש: מסמן נקודת קצה כציבורית (ללא אימות).

@Public()
@Get('health')
getHealth() {
return { status: 'ok' };
}

@Permissions(...)

שימוש: דורש הרשאות ספציפיות.

@Permissions(Permission.MANAGE_DEVICES)
@Delete(':id')
deleteDevice(@Param('id') id: string) {
// ...
}

@PlainResponse()

שימוש: מדלג על TransformInterceptor (לתגובות גולמיות).

@PlainResponse()
@Get('download/:id')
downloadFile(@Param('id') id: string, @Res() res: Response) {
return res.download('path/to/file');
}

@RateLimit(limit, window)

שימוש: הגדרת הגבלת קצב מותאמת אישית.

@RateLimit(10, 60) // 10 בקשות לדקה
@Post('send-message')
sendMessage() {
// ...
}

בדיקה ופיתוח

דילוג על אבטחה בפיתוח

ב-.env פיתוח:

NODE_ENV=development
SKIP_AUTH=true # זהירות! השתמש רק לוקאלית

זה מאפשר דילוג על JwtAuthGuard לצורך בדיקה מהירה.

בדיקת Guards ידנית

// בקובץ בדיקה (E2E)
it('should return 401 without token', async () => {
const response = await request(app.getHttpServer())
.get('/devices')
.expect(401);

expect(response.body.message).toContain('Unauthorized');
});

שיטות עבודה מומלצות

  1. אל תדלג על Guards אלא אם הנקודת קצה באמת ציבורית.
  2. השתמש ב-@Permissions תמיד כשיש צורך בהרשאה.
  3. אל תשכח @PlainResponse בהורדות קבצים (למניעת עיטוף כפול).
  4. נטר Rate Limits ב-Redis כדי לזהות שימוש חריג.
  5. בדוק AccountLockout תקופתית כדי לשחרר משתמשים תקינים.

פתרון תקלות

שגיאה: "Unauthorized" למרות אסימון תקין

סיבות:

  • האסימון פג תוקף.
  • JWT_SECRET שגוי או השתנה.
  • השרת הופעל מחדש ו-Redis נוקה.

פתרון:

# בדוק תוקף האסימון
jwt decode <your-token>

# וודא ש-JWT_SECRET תואם
echo $JWT_SECRET

שגיאה: "403 Forbidden"

סיבות:

  • למשתמש אין את ההרשאה הנדרשת.
  • החשבון נעול.

פתרון:

// בדוק בDB
db.user.findUnique({ where: { id: userId } });
// אם isLocked: true, שחרר ידנית או המתן 30 דקות.

שגיאה: "429 Too Many Requests"

סיבות:

  • חרגת מהגבלת הקצב.

פתרון:

  • המתן עד לאיפוס החלון (בדרך כלל דקה אחת).
  • או הגדל את ה-Limit:
    @RateLimit(200, 60)