Rate-Limiting: IPv6-Bypass-Härtung via ipKeyGenerator
loginRateLimiter und staffPasswordReAuthLimiter keyten auf die volle req.ip. Bei IPv6 kann ein Angreifer aus seinem zugeteilten Block (/56–/64) pro Request eine neue Adresse nehmen und so das Per-IP-Limit umgehen – betrifft Login-Bruteforce-Schutz und den Passwort-Set- Reauth-Limiter. Fix: req.ip in beiden keyGenerator durch ipKeyGenerator() ersetzt (express-rate-limit v7). IPv6 wird auf das Subnetz normalisiert (Library-Default /56), IPv4 bleibt unverändert. Verifiziert: zwei verschiedene IPv6 im selben /56 ergeben denselben Key. Die Limiter ohne eigenen keyGenerator (Passwort-Reset, Consent) normalisieren IPv6 bereits über den Library-Default – damit jetzt konsistent. Ersetzt den verworfenen aria-WIP, neu auf aktuellem Stand gebaut. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* SecurityEvent (RATE_LIMIT_HIT) – damit der Monitoring-View und das
|
||||
* Alert-System sehen, wenn jemand auf die Tür hämmert.
|
||||
*/
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import rateLimit, { ipKeyGenerator } from 'express-rate-limit';
|
||||
import { emit as emitSecurityEvent, contextFromRequest } from '../services/securityMonitor.service.js';
|
||||
|
||||
function onLimitReached(label: string, severity: 'MEDIUM' | 'HIGH') {
|
||||
@@ -54,7 +54,13 @@ export const loginRateLimiter = rateLimit({
|
||||
skipSuccessfulRequests: true,
|
||||
keyGenerator: (req): string => {
|
||||
const email = (req.body?.email || '').toString().trim().toLowerCase();
|
||||
const ip = req.ip || 'unknown';
|
||||
// IPv6-Härtung: ipKeyGenerator normalisiert IPv6 auf das Subnetz
|
||||
// (Default /56), damit ein Angreifer nicht durch Rotation innerhalb
|
||||
// seines zugeteilten IPv6-Blocks das Per-IP-Limit umgeht. IPv4 bleibt
|
||||
// unverändert. Die Limiter OHNE eigenen keyGenerator (Passwort-Reset,
|
||||
// Consent) machen das schon über den Library-Default – hier holen wir
|
||||
// die Custom-keyGenerator-Limiter auf denselben Stand.
|
||||
const ip = ipKeyGenerator(req.ip || 'unknown');
|
||||
return email ? `${ip}|${email}` : `${ip}|<no-email>`;
|
||||
},
|
||||
handler: (req, res, _next, options) => {
|
||||
@@ -107,7 +113,8 @@ export const staffPasswordReAuthLimiter = rateLimit({
|
||||
},
|
||||
skipSuccessfulRequests: true,
|
||||
keyGenerator: (req): string => {
|
||||
const ip = req.ip || 'unknown';
|
||||
// IPv6-Härtung wie beim Login-Limiter (siehe dort).
|
||||
const ip = ipKeyGenerator(req.ip || 'unknown');
|
||||
const targetUserId = (req.params?.id ?? '<missing>').toString();
|
||||
return `${ip}|staff-pw|${targetUserId}`;
|
||||
},
|
||||
|
||||
@@ -97,6 +97,20 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
||||
|
||||
## ✅ Erledigt
|
||||
|
||||
- [x] **🔒 Rate-Limiting: IPv6-Bypass-Härtung (ipKeyGenerator)**
|
||||
- Die Rate-Limiter mit eigenem `keyGenerator` (`loginRateLimiter`,
|
||||
`staffPasswordReAuthLimiter`) keyten auf die **volle** `req.ip`.
|
||||
Bei IPv6 kann ein Angreifer aus seinem zugeteilten Block (/56–/64)
|
||||
pro Versuch eine neue Adresse nehmen und so das Per-IP-Limit
|
||||
(Login-Bruteforce, Passwort-Set-Reauth) umgehen.
|
||||
- Fix: `req.ip` in beiden `keyGenerator` durch `ipKeyGenerator(...)`
|
||||
(express-rate-limit v7) ersetzt → IPv6 wird auf das Subnetz
|
||||
normalisiert (Library-Default /56), IPv4 unverändert. Verifiziert:
|
||||
zwei verschiedene IPv6 im selben /56 ⇒ derselbe Key.
|
||||
- Die Limiter OHNE eigenen keyGenerator (Passwort-Reset, Consent)
|
||||
machten das schon über den Library-Default – jetzt konsistent.
|
||||
(Ersetzt den verworfenen aria-WIP; auf aktuellem Stand neu gebaut.)
|
||||
|
||||
- [x] **🐞 Spam-Tab: Anhänge aus Junk-Ordner (Pentest R124-Fund)**
|
||||
- Beim Spam-Feature wurden `moveEmailToTrash`/`restoreEmailFromTrash`
|
||||
auf den echten Junk-Pfad umgestellt, aber vier Attachment-Funktionen
|
||||
|
||||
Reference in New Issue
Block a user