API Rate Limiting Implementieren
API Rate Limiting richtig implementieren
Rate Limiting schützt Ihre API vor Überlastung und Missbrauch. Dieser Guide erklärt verschiedene Algorithmen und zeigt praktische Implementierungen.
Warum Rate Limiting?
- DDoS-Schutz: Überlastungsangriffe abwehren
- Faire Nutzung: Ressourcen gleichmäßig verteilen
- Kosten kontrollieren: API-Kosten begrenzen
- Stabilität: System vor Überlastung schützen
Rate Limiting Algorithmen
1. Fixed Window
Einfachster Ansatz: Zähler pro Zeitfenster (z.B. pro Minute)
Minute 1: Request 1, 2, 3... 100 ✅ Minute 1: Request 101 ❌ (Limit erreicht) Minute 2: Zähler reset, Request 1 ✅
Problem: Burst am Fensterende + Anfang = doppelte Last
2. Sliding Window Log
Speichert Timestamps aller Requests, zählt im gleitenden Fenster.
// Prüfe: Wie viele Requests in den letzten 60 Sekunden? Requests: [12:00:30, 12:00:45, 12:01:10, 12:01:25] Jetzt: 12:01:30 Im Fenster (letzte 60s): 3 Requests
3. Token Bucket
Beliebtester Algorithmus. Tokens werden kontinuierlich aufgefüllt.
Bucket: 10 Tokens (max)
Refill: 1 Token pro Sekunde
Request → Token verfügbar? → Ja: Entfernen, Request erlauben
→ Nein: Rate Limit Error (429)
4. Leaky Bucket
Requests werden in Queue gestellt und mit fester Rate verarbeitet.
HTTP Response Headers
| Header | Beschreibung |
|---|---|
X-RateLimit-Limit |
Maximale Requests pro Fenster |
X-RateLimit-Remaining |
Verbleibende Requests |
X-RateLimit-Reset |
Unix-Timestamp für Reset |
Retry-After |
Sekunden bis zum Retry |
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1699999999
Retry-After: 30
{"error": "Rate limit exceeded. Try again in 30 seconds."}
Node.js Implementation
Mit express-rate-limit
const rateLimit = require('express-rate-limit');
// Basis Rate Limiter
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 Minuten
max: 100, // 100 Requests pro Fenster
message: { error: 'Too many requests, please try again later.' },
standardHeaders: true, // RateLimit-* Headers
legacyHeaders: false,
});
app.use('/api/', limiter);
// Stricter für Auth-Endpoints
const authLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 Stunde
max: 5, // 5 Login-Versuche
message: { error: 'Too many login attempts.' }
});
app.use('/api/auth/login', authLimiter);
Mit Redis (für verteilte Systeme)
const RedisStore = require('rate-limit-redis');
const Redis = require('ioredis');
const client = new Redis();
const limiter = rateLimit({
store: new RedisStore({
sendCommand: (...args) => client.call(...args),
}),
windowMs: 15 * 60 * 1000,
max: 100,
});
PHP Implementation
<?php
class RateLimiter {
private Redis $redis;
private int $maxRequests;
private int $windowSeconds;
public function __construct(Redis $redis, int $max = 100, int $window = 60) {
$this->redis = $redis;
$this->maxRequests = $max;
$this->windowSeconds = $window;
}
public function isAllowed(string $identifier): array {
$key = "ratelimit:{$identifier}";
$current = (int) $this->redis->get($key);
if ($current >= $this->maxRequests) {
$ttl = $this->redis->ttl($key);
return [
'allowed' => false,
'remaining' => 0,
'retryAfter' => $ttl
];
}
$this->redis->multi();
$this->redis->incr($key);
$this->redis->expire($key, $this->windowSeconds);
$this->redis->exec();
return [
'allowed' => true,
'remaining' => $this->maxRequests - $current - 1,
'retryAfter' => 0
];
}
}
// Verwendung
$limiter = new RateLimiter($redis, 100, 60);
$clientIP = $_SERVER['REMOTE_ADDR'];
$result = $limiter->isAllowed($clientIP);
header("X-RateLimit-Limit: 100");
header("X-RateLimit-Remaining: {$result['remaining']}");
if (!$result['allowed']) {
http_response_code(429);
header("Retry-After: {$result['retryAfter']}");
echo json_encode(['error' => 'Rate limit exceeded']);
exit;
}
Nginx Rate Limiting
# Rate Limit Zone definieren
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
server {
# API: 10 req/s mit Burst von 20
location /api/ {
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
proxy_pass http://backend;
}
# Login: Strenger
location /api/auth/login {
limit_req zone=login burst=5;
limit_req_status 429;
proxy_pass http://backend;
}
}
Best Practices
- Verschiedene Limits für verschiedene Endpoints
- Authentifizierte User: Höhere Limits
- Immer Rate-Limit-Headers senden
- Aussagekräftige Fehlermeldungen
- Redis für verteilte Systeme
- Monitoring und Alerting einrichten
Rate Limit pro Ebene
| Ebene | Beispiel-Limit | Zweck |
|---|---|---|
| Global | 10.000/min | DDoS-Schutz |
| Pro IP | 100/min | Einzelne Clients |
| Pro User | 1.000/min | Authentifizierte User |
| Pro API-Key | Variabel | Nach Plan |