- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks - Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists - Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services - Add Microsoft OIDC SSO, API token management, and user lifecycle features - Add swagger-ui vendor integration and OpenAPI spec - Add production Docker setup and bin/ scripts - Update composer dependencies, config, templates, and frontend assets throughout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3.3 KiB
3.3 KiB
Anfragelimits (Rate Limiting)
Letzte Aktualisierung: 2026-02-21
Dieses Dokument beschreibt das aktuelle zentrale Rate-Limiting für Login und API.
Ziel
- Brute-Force auf Login reduzieren.
- API-Missbrauch (Burst/Spam) abfangen.
- Einheitliches Verhalten mit
429+Retry-After.
Technischer Aufbau
Storage
Tabelle: request_rate_limits
Spalten:
scope: Technischer Bereich (z. B.login.password.email_ip)subject_hash: SHA-256 Hash des Subjects (keine Klartexte)hits: Treffer im aktuellen Fensterwindow_started_at: Beginn des aktuellen Zeitfensters (UTC)blocked_until: Block-Ende (UTC),NULLwenn nicht geblockt
Schema:
- Tabelle wird in
db/init/init.sqlmit angelegt. - Für Bestandsumgebungen sollte ein idempotentes SQL-Update bereitgestellt werden.
Service/Repository
- Service:
/lib/Service/Security/RateLimiterService.php - Repository:
/lib/Repository/Security/RateLimitRepository.php
Der Service ist absichtlich fail-open:
- Wenn DB/Storage fehlschlägt, wird kein harter Lock erzeugt.
- Requests laufen weiter, um Verfügbarkeit nicht zu brechen.
API Rate Limiting
Integration:
/lib/Http/ApiBootstrap.php(vor Auth)
Aktuelle Limits:
- Bearer vorhanden (
token + ip)
- Scope:
api.token_ip - Key:
<selector>|<ip> - Limit:
300Hits pro60Sekunden - Block:
120Sekunden
- Kein Bearer (
ip-only)
- Scope:
api.ip - Key:
<ip> - Limit:
120Hits pro60Sekunden - Block:
120Sekunden
Bei überschreitung:
- Response:
429 - Body:
{"error":"rate_limit_exceeded"} - Header:
Retry-After: <sekunden>
Login Rate Limiting
Integration:
/pages/auth/login().php
Aktuelle Limits:
- Schritt
resolve_email(IP)
- Scope:
login.resolve.ip - Key:
<ip> - Limit:
25Hits pro600Sekunden - Block:
300Sekunden
- Schritt
login_password(email + ip)
- Scope:
login.password.email_ip - Key:
<lowercase-email>|<ip> - Limit:
5Fehlversuche pro900Sekunden - Block:
900Sekunden
Verhalten:
- Bei Block: HTTP
429+Retry-After. - UI zeigt generische Meldung:
Too many login attempts. Please wait and try again. - Bei erfolgreichem Passwort-Login wird der Passwort-Scope für diesen Key zurückgesetzt.
Datenfluss pro Request
- Key bilden (
scope+ Subject) - Subject hashen (
sha256) - Bestehenden Datensatz lesen
- Falls
blocked_until > now: direkt blocken - Fenster prüfen (
window_started_at + windowSeconds) - Hits erhöhen
- Bei
hits > max:blocked_until = now + blockSeconds - Ergebnis liefern (
allowed,retry_after)
Operative Hinweise
- Zeitbasis ist UTC (
gmdate). - Tabelle kann wachsen; in V1 gibt es noch keinen automatischen Cleanup für alte Rate-Limit-Zeilen.
- Bei Bedarf kann ein Wartungsjob alte/obsolete Zeilen periodisch löschen.
Smoke-Test (manuell)
API:
- Schnell >120 Requests/min ohne Bearer gegen
/api/v1/* - Erwartung:
429mitRetry-After
Login:
- Mehrere falsche Passwortversuche für dieselbe Email+IP
- Erwartung nach 5 Fehlversuchen:
429und Sperre für 15 Minuten
Erweiterungen (nächster Schritt)
- Limits in Settings pflegbar machen (statt Hardcode).
- Optional stricter Mode in Production (fail-closed nur für API).
- Cleanup-Job für
request_rate_limits. - Optional Logging/Stats für geblockte Requests (z. B. im Admin-Stats Modul).