Rate-Limit-Sperren: Admin-UI zum Freigeben

Bei zu vielen Login-Fehlversuchen war ohne Container-Restart kein Weg
zurück. Jetzt sehen Admins die aktiven Sperren und können einzeln
freigeben.

Backend:
- GET  /api/settings/rate-limits/active (settings:read)
  Liest SecurityEvent RATE_LIMIT_HIT der letzten 15 Min, gruppiert nach
  IP, liefert lastEmail/limiters/hitCount/lastHit.
- POST /api/settings/rate-limits/reset (settings:update)
  Body { ipAddress } → ruft loginRateLimiter.resetKey + passwordReset-
  RateLimiter.resetKey auf (express-rate-limit v7), audited als
  UPDATE auf resourceType=RateLimit.

Frontend:
- Neue Seite /settings/rate-limits: Tabelle mit IP/Email/Limiter/Hits/
  Letzter-Hit/Aktion. Auto-Refresh alle 15s. Freigeben-Button pro IP.
- Kachel in Settings-Übersicht (orange, ShieldOff-Icon, settings:read).

Live-verifiziert: 11 failed Logins → 429 ab dem 11.; Liste zeigt
IP + Email; POST /reset → 200; danach wieder 401 statt 429; Audit-Log
„Rate-Limit für IP 127.0.0.1 manuell freigegeben" angelegt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-17 01:20:43 +02:00
parent 69b9a35674
commit 956bc394b8
7 changed files with 338 additions and 1 deletions
+20
View File
@@ -1007,6 +1007,26 @@ export const backupApi = {
},
};
// Rate-Limit-Verwaltung (Admin)
export interface ActiveRateLimit {
ipAddress: string;
lastHit: string;
hitCount: number;
lastEmail: string | null;
lastEndpoint: string | null;
limiters: string[];
}
export const rateLimitApi = {
getActive: async () => {
const res = await api.get<ApiResponse<ActiveRateLimit[]>>('/settings/rate-limits/active');
return res.data;
},
reset: async (ipAddress: string) => {
const res = await api.post<ApiResponse<void>>('/settings/rate-limits/reset', { ipAddress });
return res.data;
},
};
// Platforms
export const platformApi = {
getAll: async (includeInactive = false) => {