security(api): Add rate limiting to prevent abuse #205

Closed
opened 2026-01-24 17:14:55 +00:00 by jack · 0 comments
Owner

Problem

Keine Rate-Limiting auf API Endpoints:

  • Potenzielle DoS-Anfälligkeit
  • Unbegrenzter Ressourcenverbrauch
  • Worker können überlastet werden

Lösung

1. Rate Limiter Middleware

// packages/backend/src/middleware/rate-limit.ts
import rateLimit from 'express-rate-limit';
import slowDown from 'express-slow-down';

// Standard Rate Limit
export const standardLimiter = rateLimit({
  windowMs: 60 * 1000,  // 1 Minute
  max: 100,             // 100 requests per minute
  message: { error: 'Too many requests, please try again later' },
  standardHeaders: true,
  legacyHeaders: false,
});

// Stricter für teure Operationen
export const expensiveLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 20,              // 20 requests per minute
  message: { error: 'Rate limit exceeded for expensive operations' },
});

// Speed Limiter (verlangsamt statt blockiert)
export const speedLimiter = slowDown({
  windowMs: 60 * 1000,
  delayAfter: 50,       // Nach 50 requests...
  delayMs: (hits) => hits * 100,  // ...pro Request 100ms mehr Delay
});

// Search-spezifisch
export const searchLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 30,              // Search ist teuer
});

2. Anwendung auf Routes

// packages/backend/src/routes/index.ts
import { standardLimiter, expensiveLimiter, searchLimiter } from '../middleware/rate-limit';

// Global für alle Routes
app.use('/api', standardLimiter);

// Spezifisch für teure Operationen
app.use('/api/data/analytics', expensiveLimiter);
app.use('/api/search', searchLimiter);
app.use('/api/data/observations/bulk', expensiveLimiter);

// Worker-Spawning begrenzen
app.use('/api/worker/spawn', rateLimit({
  windowMs: 60 * 1000,
  max: 5,  // Max 5 Worker-Spawns pro Minute
}));

3. Per-Project Rate Limiting

// Für Multi-Tenant Szenarien
const projectLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 50,
  keyGenerator: (req) => {
    const project = req.query.project || req.body?.project || 'default';
    return `${req.ip}:${project}`;
  },
});

4. Backpressure für Task Queue

// Bevor neue Tasks gequeued werden
async queueTask(task: CreateTaskInput): Promise<Task> {
  const pendingCount = await this.taskRepo.countByStatus('pending');
  
  if (pendingCount > 1000) {
    throw new AppError('Task queue full, please try again later', 429);
  }
  
  return this.taskRepo.create(task);
}

Rate Limits Übersicht

Endpoint Limit Window
Standard API 100/min 1 min
Analytics 20/min 1 min
Search 30/min 1 min
Bulk Operations 20/min 1 min
Worker Spawn 5/min 1 min
Task Queue 1000 pending max -

Akzeptanzkriterien

  • Rate Limiter Middleware implementiert
  • Auf alle relevanten Endpoints angewendet
  • Sinnvolle Limits pro Endpoint-Typ
  • Backpressure für Task Queue
  • Klare Fehlermeldungen (429 Status)
  • Rate Limit Headers in Response
## Problem Keine Rate-Limiting auf API Endpoints: - Potenzielle DoS-Anfälligkeit - Unbegrenzter Ressourcenverbrauch - Worker können überlastet werden ## Lösung ### 1. Rate Limiter Middleware ```typescript // packages/backend/src/middleware/rate-limit.ts import rateLimit from 'express-rate-limit'; import slowDown from 'express-slow-down'; // Standard Rate Limit export const standardLimiter = rateLimit({ windowMs: 60 * 1000, // 1 Minute max: 100, // 100 requests per minute message: { error: 'Too many requests, please try again later' }, standardHeaders: true, legacyHeaders: false, }); // Stricter für teure Operationen export const expensiveLimiter = rateLimit({ windowMs: 60 * 1000, max: 20, // 20 requests per minute message: { error: 'Rate limit exceeded for expensive operations' }, }); // Speed Limiter (verlangsamt statt blockiert) export const speedLimiter = slowDown({ windowMs: 60 * 1000, delayAfter: 50, // Nach 50 requests... delayMs: (hits) => hits * 100, // ...pro Request 100ms mehr Delay }); // Search-spezifisch export const searchLimiter = rateLimit({ windowMs: 60 * 1000, max: 30, // Search ist teuer }); ``` ### 2. Anwendung auf Routes ```typescript // packages/backend/src/routes/index.ts import { standardLimiter, expensiveLimiter, searchLimiter } from '../middleware/rate-limit'; // Global für alle Routes app.use('/api', standardLimiter); // Spezifisch für teure Operationen app.use('/api/data/analytics', expensiveLimiter); app.use('/api/search', searchLimiter); app.use('/api/data/observations/bulk', expensiveLimiter); // Worker-Spawning begrenzen app.use('/api/worker/spawn', rateLimit({ windowMs: 60 * 1000, max: 5, // Max 5 Worker-Spawns pro Minute })); ``` ### 3. Per-Project Rate Limiting ```typescript // Für Multi-Tenant Szenarien const projectLimiter = rateLimit({ windowMs: 60 * 1000, max: 50, keyGenerator: (req) => { const project = req.query.project || req.body?.project || 'default'; return `${req.ip}:${project}`; }, }); ``` ### 4. Backpressure für Task Queue ```typescript // Bevor neue Tasks gequeued werden async queueTask(task: CreateTaskInput): Promise<Task> { const pendingCount = await this.taskRepo.countByStatus('pending'); if (pendingCount > 1000) { throw new AppError('Task queue full, please try again later', 429); } return this.taskRepo.create(task); } ``` ## Rate Limits Übersicht | Endpoint | Limit | Window | |----------|-------|--------| | Standard API | 100/min | 1 min | | Analytics | 20/min | 1 min | | Search | 30/min | 1 min | | Bulk Operations | 20/min | 1 min | | Worker Spawn | 5/min | 1 min | | Task Queue | 1000 pending max | - | ## Akzeptanzkriterien - [ ] Rate Limiter Middleware implementiert - [ ] Auf alle relevanten Endpoints angewendet - [ ] Sinnvolle Limits pro Endpoint-Typ - [ ] Backpressure für Task Queue - [ ] Klare Fehlermeldungen (429 Status) - [ ] Rate Limit Headers in Response
jack closed this issue 2026-01-25 00:00:09 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
customable/claude-mem#205
No description provided.