Rate Limiting in Node.js: Schutz von APIs vor Überlastung und Angreifern
\n\nRate Limiting (Anfragegeschwindigkeitsbegrenzung) ist ein kritisch wichtiger Mechanismus für jede Webanwendung in Node.js. Er ermöglicht es, die Anzahl der Anfragen zu kontrollieren, die ein Client innerhalb eines bestimmten Zeitraums an den Server senden kann. Ohne Rate Limiting ist Ihre API anfällig für DDoS-Angriffe, zufällige Überlastungen und übermäßigen Ressourcenverbrauch.
\n\nWarum ist Rate Limiting notwendig?
\n- \n
- Schutz vor Brute-Force: Verhindert mehrfache Anmeldeversuche. \n
- DDoS-Prävention: Begrenzt die Auswirkungen von Denial-of-Service-Angriffen. \n
- Faire Ressourcenverteilung: Garantiert gleichen Zugang für alle Benutzer. \n
- Kosteneinsparung: Reduziert die Last auf Servern und Datenbanken. \n
- SLA-Einhaltung: Erfüllung von Service-Level-Agreements. \n
Wichtige Rate-Limiting-Algorithmen
\nEs gibt mehrere Ansätze zur Implementierung der Geschwindigkeitsbegrenzung. Betrachten wir die gängigsten:
\n\n1. Sliding Window (Gleitendes Fenster)
\nDer häufigste Algorithmus. Anfragen werden in Zeitfenstern gruppiert (z. B. 1 Minute). Überschreitet die Anzahl der Anfragen das Limit, werden weitere Anfragen bis zum Beginn eines neuen Fensters abgelehnt.
\n\n2. Token Bucket (Token-Eimer)
\nEin virtueller "Eimer" enthält Token. Jede Anfrage verbraucht einen Token. Token werden mit einer festen Rate aufgefüllt. Ist der Eimer leer, wird die Anfrage abgelehnt.
\n\n3. Leaky Bucket (Undichter Eimer)
\nAnfragen gelangen in eine Warteschlange und werden mit konstanter Geschwindigkeit verarbeitet. Wenn die Warteschlange überläuft, werden Anfragen verworfen.
\n\nBibliotheken für Rate Limiting in Node.js
\n\n1. express-rate-limit
\nDie beliebteste Bibliothek für Express.js. Einfach zu verwenden und anpassbar.
\n\nconst rateLimit = require('express-rate-limit');\n\n// Middleware zur Anfragebegrenzung erstellen\nconst limiter = rateLimit({\n windowMs: 15 * 60 * 1000, // 15 Minuten\n max: 100, // maximal 100 Anfragen pro Fenster\n message: 'Zu viele Anfragen, bitte später versuchen.',\n standardHeaders: true, // Gibt RateLimit-*-Header zurück\n legacyHeaders: false, // Deaktiviert X-RateLimit-*-Header\n});\n\n// Auf alle Routen anwenden\napp.use(limiter);\n\n// Oder nur auf eine bestimmte Route\napp.use('/api/login', limiter);\n\n\n2. bottleneck
\nEine universelle Bibliothek, die mit beliebigen asynchronen Operationen arbeitet. Unterstützt die Algorithmen Token Bucket und Leaky Bucket.
\n\nconst Bottleneck = require('bottleneck');\n\n// Limiter erstellen: 5 Anfragen pro Sekunde\nconst limiter = new Bottleneck({\n minTime: 200, // 200 ms zwischen Anfragen\n maxConcurrent: 5, // maximal 5 gleichzeitige Anfragen\n reservoir: 100, // anfängliche Token-Anzahl\n reservoirRefreshAmount: 100,\n reservoirRefreshInterval: 60 * 1000, // Auffüllung einmal pro Minute\n});\n\n// Funktion in Limiter einschließen\nasync function fetchData(url) {\n const response = await fetch(url);\n return response.json();\n}\n\nconst limitedFetch = limiter.wrap(fetchData);\n\n// Verwendung\nconst data = await limitedFetch('https://api.example.com/data');\n\n\n3. rate-limiter-flexible
\nEine flexible Bibliothek mit Unterstützung für Redis, MongoDB, Memcached und andere Speicher. Ideal für verteilte Systeme.
\n\nconst { RateLimiterRedis } = require('rate-limiter-flexible');\nconst Redis = require('ioredis');\n\nconst redisClient = new Redis();\n\nconst rateLimiter = new RateLimiterRedis({\n storeClient: redisClient,\n keyPrefix: 'middleware',\n points: 10, // 10 Anfragen\n duration: 1, // pro 1 Sekunde\n});\n\napp.use(async (req, res, next) => {\n try {\n await rateLimiter.consume(req.ip);\n next();\n } catch (rejRes) {\n res.status(429).send('Zu viele Anfragen');\n }\n});\n