Jeder Auth-Endpoint ist ein potenzielles Brute-Force-Ziel — Login, Passwort-Reset, MFA-Code-Verifikation, Token-Refresh. Ohne Rate-Limits kann ein:e Angreifer:in Millionen Versuche durchprobieren. Die naive Antwort „IP nach 5 Fehlversuchen sperren" reicht heute nicht mehr — distributed Brute-Force (Credential Stuffing über Botnetze) umgeht IP-basierte Limits. Dieser Artikel zeigt die mehrdimensionalen Limit-Patterns, das Lockout-vs.-Slowdown-Dilemma und die Anti-Bot-Werkzeuge der 2020er.
Die drei Angriffs-Typen
| Typ | Was es ist | Was es braucht |
|---|---|---|
| Klassisches Brute-Force | Ein Account, viele Passwort-Versuche | Username/E-Mail des Opfers |
| Credential Stuffing | Viele Accounts mit geleakten Pwd-Pairs | Datenleck-Liste (Mail + Passwort) |
| Password Spraying | Viele Accounts, wenige Passwörter | User-Liste + Standard-Passwörter („Sommer2024!", „Passwort123") |
Konsequenzen:
- Klassisches Brute-Force ist heute selten erfolgreich — gegen einen einzigen Account mit gutem Passwort sind 1 Mio. Versuche nutzlos.
- Credential Stuffing ist die häufigste echte Bedrohung. Geleakte
mail@example.com:password123-Listen werden gegen Hunderte Sites durchprobiert. Wenn der User dasselbe Passwort woanders nutzt — Account-Übernahme. - Password Spraying umgeht klassische Lockout-Mechanismen, weil pro Account nur ein paar Versuche kommen — fällt unter den Threshold.
Lockout vs. Slowdown vs. Captcha
Lockout: Nach N Fehlversuchen wird der Account für X Minuten gesperrt.
- Plus: Klare Defense.
- Minus: DoS-Vektor — Angreifer kann jeden Account beliebig sperren (Username-Liste durchprobieren mit falschen Passwörtern). Vor allem bei Massnahmen, die User „aussperren", anfällig.
Slowdown (Exponential Backoff): Nach N Fehlversuchen wird die Antwort um wachsende Zeit verzögert (1s, 2s, 4s, 8s, ...).
- Plus: Kein DoS — User wartet länger, aber kein Aussperren.
- Minus: Erfordert State pro Account, weniger absolute Sicherheit.
Captcha (hCaptcha, Cloudflare Turnstile, reCAPTCHA): Nach N Fehlversuchen verlangt der Server zusätzlich Captcha-Lösung.
- Plus: Blockt Bots effektiv.
- Minus: UX-Hürde, Privacy-Probleme bei manchen Providern (reCAPTCHA tracked).
Konsens (Stand 2026): Kombinieren.
// Layer 1: globales IP-Rate-Limit (gegen offensichtliche Floods)
app.use('/login', rateLimit({ keyGenerator: req => req.ip, max: 30, window: '5m' }));
// Layer 2: pro Account (gegen klassisches Brute-Force)
async function checkAccountLimit(email) {
const fails = await counter.get(`login:fails:${email}`);
if (fails > 10) throw new Error('Captcha required');
if (fails > 5) await sleep(Math.min(1000 * 2 ** (fails - 5), 30000)); // Slowdown
}
// Layer 3: Captcha bei verdächtigem Verhalten
// (z. B. via Cloudflare Turnstile vor Login-Submit, ab N Versuchen)
// Layer 4: User-Notification bei verdächtigen Versuchen
if (fails > 3) {
await sendMail(user.email, 'Mehrere fehlgeschlagene Login-Versuche auf deinem Konto.');
}Distributed Brute-Force / Credential Stuffing
Wenn der Angreifer ein Botnetz mit Tausenden IPs nutzt, jedes mit nur einem Versuch — klassisches IP-Rate-Limit greift nicht.
Indikatoren:
- Login-Versuche aus geografisch sehr unterschiedlichen IPs binnen Minuten.
- User-Agent-Diversität, die nicht zu echtem User-Verhalten passt.
- Pro Account nur 1–2 Fehlversuche — kommt unterhalb des klassischen Thresholds an.
Schutz-Schichten:
- Bot-Detection (Cloudflare Bot Management, AWS WAF, hCaptcha) — erkennt Browser-Fingerprint-Anomalien, Headless-Browser, Tooling-Signaturen.
- Compromised-Password-Check beim Login — vergleicht eingegebenes Passwort gegen Have-I-Been-Pwned-API (k-Anonymity-Modus). Wenn ein Passwort aus Lecks bekannt ist und der User es trotzdem nutzt, ist das Credential-Stuffing-Risiko hoch.
- Risk-Based Authentication — Login-Pattern-Anomalien (neuer Standort, neues Gerät, ungewöhnliche Zeit) triggern Step-Up (MFA, Passkey, Captcha).
- Velocity-Checks über mehrere Dimensionen — nicht nur „IP", sondern „User-Agent + IP-Subnet + Zeitfenster" als zusammengesetzter Key.
const crypto = require('crypto');
async function isPasswordCompromised(password) {
const sha1 = crypto.createHash('sha1').update(password).digest('hex').toUpperCase();
const prefix = sha1.slice(0, 5);
const suffix = sha1.slice(5);
const response = await fetch(`https://api.pwnedpasswords.com/range/${prefix}`);
const text = await response.text();
return text.split('\n').some(line => line.startsWith(suffix));
}
// Beim Sign-up oder Passwort-Change blockieren
if (await isPasswordCompromised(newPassword)) {
return res.status(400).send('Dieses Passwort taucht in bekannten Lecks auf — bitte ein anderes.');
}Der k-Anonymity-Trick: nur die ersten 5 Zeichen des SHA-1-Hashes gehen über die Leitung; HIBP liefert alle passenden Suffixe; der Server filtert lokal. Keine vollständigen Passwort-Hashes verlassen den Server.
Rate-Limit-Architektur
Wo läuft das Limit?
| Layer | Vorteil | Nachteil |
|---|---|---|
| Reverse-Proxy (nginx, Caddy, Cloudflare) | Vor App, blockt früh, IP-basiert | Begrenzt auf IP-Layer-Info |
| App-Middleware (express-rate-limit etc.) | Granular, User-/Endpoint-Limits | Hash-Bombing trifft trotzdem App-Server |
| API-Gateway (Kong, Tyk, AWS) | Zentral für Microservices | Setup-Aufwand |
| Distributed Cache (Redis) | Multi-Instance-konsistent | Single Point of Failure |
Empfehlung: Reverse-Proxy für grobe IP-Floods + App-Middleware mit Redis für feine Limits pro User/Endpoint. Damit ist sowohl Layer-7-DDoS als auch Auth-Brute-Force gedeckt.
Token-Bucket vs. Sliding-Window:
- Token-Bucket — User hat N Tokens, jeder Request verbraucht einen, Refill über Zeit. Klassisch.
- Sliding-Window — letzte X Sekunden zählen, fairer bei Burst-Verhalten.
- Fixed-Window — pro Zeitslot ein Counter. Einfach, anfällig für „grad nach Slot-Wechsel"-Bursts.
Praktisch: Sliding-Window-Approximation (z. B. Cloudflare Rate Limiting) ist State-of-the-Art.
Was alles rate-limited werden muss
Nicht nur Login. Eine vollständige Auth-Architektur hat viele Rate-Limit-Ziele:
| Endpoint | Risk ohne Limit | Empfohlener Limit |
|---|---|---|
| POST /login | Brute-Force | 5–10/min pro IP+E-Mail |
| POST /forgot-password | Mail-Bombing, Reset-Spam | 3/h pro E-Mail |
| POST /register | Bot-Account-Erstellung | 5/h pro IP |
| POST /verify-mfa | MFA-Code-Brute-Force | 5/min pro User |
| GET /verify-email | Token-Brute-Force | 10/min pro IP |
| POST /auth/refresh | Refresh-Token-Replay | 10/min pro Token |
| POST /api/... | Generelle API-Abuse | je nach Endpoint |
| GET /api/users/search | User-Enumeration via Suche | 30/min pro User |
Frist-übergreifender Limit: auch pro User absolute Limits pro Tag/Woche (z. B. max. 50 Login-Versuche pro Tag pro User).
MFA-Code-Brute-Force
Ein klassisch unterschätzter Vektor: 6-stellige TOTP-Codes. Nur 1 Mio. Möglichkeiten. Ohne Rate-Limit ist Brute-Force in Minuten machbar.
Schutz:
- Strikter Rate-Limit pro User: 5 Versuche pro 5 Minuten, danach 15 Min. Lockout der MFA-Prüfung (nicht des Accounts).
- Code-Single-Use: verwendete TOTP-Codes für ihre Validitätsperiode (typisch 30s + Drift-Window) merken, doppelte Eingabe ablehnen.
- MFA-Bypass via Race-Condition schützen: bei parallelen Anfragen mit verschiedenen Codes Lock auf User-Ebene.
Vorfälle:
- Instagram 2019 — Brute-Force gegen MFA-Code möglich, 6-stellig + kein Rate-Limit. CVE / Bug-Bounty.
- PayPal-ähnliche Vorfälle in Banking-Apps regelmäßig.
CAPTCHA-Wahl
Optionen:
| Provider | Privacy | UX | Bot-Detection |
|---|---|---|---|
| Google reCAPTCHA v3 | Schlecht (Tracking) | Unsichtbar | Sehr gut |
| hCaptcha | Besser (EU-Server-Option) | Tap-Challenge | Gut |
| Cloudflare Turnstile | Gut (kein Tracking) | Mostly invisible | Gut, JS-Challenge |
| mCaptcha / Eigenes PoW | Sehr gut | Compute-Challenge | Mittel |
Empfehlung: Cloudflare Turnstile oder hCaptcha als pragmatischer Default. Privacy-bewusste Apps können mit Proof-of-Work-Schemata (mCaptcha, FriendlyCaptcha) experimentieren.
Wann CAPTCHA triggern:
- Nicht bei jedem Login (UX-Killer).
- Adaptiv: nach N Fehlversuchen, bei verdächtigen IPs (Reputation-Listen), bei neuen Geräten.
- Stand 2026 verschieben sich Captchas zu „Bot-Score-basiert" — Browser-Fingerprint, JS-Challenges, ohne sichtbare Interaktion.
Velocity- und Verhaltens-Anomalie
Moderne Auth-Stacks gehen über klassisches Rate-Limiting hinaus zu Risk-Based Authentication:
Signale, die ein Risiko-Score erhöhen:
- Login aus ungewöhnlicher Geo-Region.
- Login zu ungewöhnlicher Zeit (3 Uhr morgens, sonst nie).
- Neues Gerät / neuer User-Agent.
- Wechsel von Privatadresse zu VPN/Tor.
- Mehrere Logins in kurzer Zeit aus unterschiedlichen Geo-Regionen (Impossible Travel).
Reaktionen bei hohem Score:
- Step-Up zu MFA (auch wenn User „remember me" aktiv hat).
- Captcha einblenden.
- Notification-Mail an User.
- Im Extremfall: Login ablehnen mit Hinweis „Bitte über Recovery-Pfad bestätigen".
Implementierungs-Optionen:
- Standalone-Libraries (selbst gebaut mit Redis-State).
- Cloud-Provider-Services (AWS Cognito Adaptive Auth, Auth0 Adaptive MFA).
- Spezialisierte Anbieter (Castle, Stytch, AWS GuardDuty).
Häufige Stolperfallen
X-Forwarded-For-Trust ohne Whitelist
Hinter einem Reverse-Proxy hat der App-Server typischerweise nur die Proxy-IP. Echte Client-IP kommt im X-Forwarded-For-Header. Wer den Header ungeprüft als „Client-IP" nutzt, lässt jede:n Angreifer:in den eigenen Rate-Limit umgehen — Header ist user-kontrolliert. Sicher: nur Trust für bekannte Reverse-Proxy-IPs setzen, ansonsten verwerfen.
Account-Lockout als DoS-Vektor
„Nach 5 Fehlversuchen Konto sperren" ist ein klassischer DoS-Vektor: Angreifer probiert systematisch falsche Passwörter und sperrt alle User aus. Slowdown oder Captcha sind die besseren Defaults; harter Lockout nur in Spezialfällen (sehr sensitive Apps mit kleinem User-Kreis).
Login-Endpoint mit hash-Bombing
Wenn argon2id-Hashing 500 ms dauert und der Login-Endpoint kein Rate-Limit hat, sind 100 parallele Requests = 50 Sekunden CPU-Belastung. Login-Endpoint ist als asymmetrisch teuer einzustufen — Rate-Limit ist nicht nur gegen Brute-Force, sondern auch gegen Hash-DoS.
MFA-Code als 6-stellige Schwachstelle ohne Rate-Limit
TOTP-Code ist 1 Mio. Möglichkeiten. Mit 5 Versuchen pro Code-Fenster (30s) und keinem Lockout-Mechanismus knacken Bots das in 60 Tagen — auf einem einzigen Account. Strikter Rate-Limit pro User auf MFA-Verifikations-Endpoint ist Pflicht, nicht optional.
Distributed Botnetze umgehen IP-Limits
Modernes Credential Stuffing nutzt Residential-Proxy-Netzwerke (gekaufte IP-Pools über kompromittierte Geräte). Jeder Request kommt aus einer anderen IP — IP-basierter Rate-Limit greift nicht. Schutz nur über mehrere Dimensionen: Browser-Fingerprint, Verhaltens-Signale, kompromittierte Passwörter (HIBP), Bot-Detection-Services.
Reset-Token-Brute-Force vergessen
Wenn der Reset-Token nur 8 Zeichen lang ist (z. B. UUIDv4 abgeschnitten) und der Reset-Endpoint kein Rate-Limit hat, kann Brute-Force in 24 Stunden erfolgreich sein. Minimum: 32 Bytes Random, plus Endpoint-Rate-Limit pro IP.
Logging ohne Filter leakt Login-Versuche
Wenn das Logging das volle Request-Body inkl. Passwort enthält, sind fehlgeschlagene Login-Versuche im Log mit Klartext-Passwörtern. Bei DB-Leak oder Log-Forwarding zu SaaS-Logger (Loggly, Papertrail) leakt das. Passwort-Felder vor Logging redacten — Standard-Middleware in Express, Pino, Winston.
Weiterführende Ressourcen
Externe Quellen
- OWASP Credential Stuffing Prevention
- OWASP Authentication Cheat Sheet
- OWASP Blocking Brute Force Attacks
- Have I Been Pwned API
- Cloudflare Turnstile
- hCaptcha
- express-rate-limit
- Redis Distributed Locks / Rate-Limit-Patterns