add composer-unused, comprehensive docs, and project restructure
- 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>
2026-02-22 15:27:35 +01:00
|
|
|
# Anfragelimits (Rate Limiting)
|
|
|
|
|
|
2026-02-24 08:49:40 +01:00
|
|
|
Letzte Aktualisierung: 2026-02-23
|
add composer-unused, comprehensive docs, and project restructure
- 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>
2026-02-22 15:27:35 +01:00
|
|
|
|
|
|
|
|
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 Fenster
|
|
|
|
|
- `window_started_at`: Beginn des aktuellen Zeitfensters (UTC)
|
|
|
|
|
- `blocked_until`: Block-Ende (UTC), `NULL` wenn nicht geblockt
|
|
|
|
|
|
|
|
|
|
Schema:
|
|
|
|
|
- Tabelle wird in `db/init/init.sql` mit 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:
|
|
|
|
|
|
|
|
|
|
1. Bearer vorhanden (`token + ip`)
|
|
|
|
|
- Scope: `api.token_ip`
|
|
|
|
|
- Key: `<selector>|<ip>`
|
|
|
|
|
- Limit: `300` Hits pro `60` Sekunden
|
|
|
|
|
- Block: `120` Sekunden
|
|
|
|
|
|
|
|
|
|
2. Kein Bearer (`ip-only`)
|
|
|
|
|
- Scope: `api.ip`
|
|
|
|
|
- Key: `<ip>`
|
|
|
|
|
- Limit: `120` Hits pro `60` Sekunden
|
|
|
|
|
- Block: `120` Sekunden
|
|
|
|
|
|
|
|
|
|
Bei überschreitung:
|
|
|
|
|
- Response: `429`
|
|
|
|
|
- Body: `{"error":"rate_limit_exceeded"}`
|
|
|
|
|
- Header: `Retry-After: <sekunden>`
|
|
|
|
|
|
|
|
|
|
## Login Rate Limiting
|
|
|
|
|
|
|
|
|
|
Integration:
|
|
|
|
|
- `/pages/auth/login().php`
|
2026-02-24 08:49:40 +01:00
|
|
|
- `/pages/api/v1/auth/login().php` (public Login ohne Bearer)
|
add composer-unused, comprehensive docs, and project restructure
- 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>
2026-02-22 15:27:35 +01:00
|
|
|
|
|
|
|
|
Aktuelle Limits:
|
|
|
|
|
|
|
|
|
|
1. Schritt `resolve_email` (IP)
|
|
|
|
|
- Scope: `login.resolve.ip`
|
|
|
|
|
- Key: `<ip>`
|
|
|
|
|
- Limit: `25` Hits pro `600` Sekunden
|
|
|
|
|
- Block: `300` Sekunden
|
|
|
|
|
|
|
|
|
|
2. Schritt `login_password` (email + ip)
|
|
|
|
|
- Scope: `login.password.email_ip`
|
|
|
|
|
- Key: `<lowercase-email>|<ip>`
|
|
|
|
|
- Limit: `5` Fehlversuche pro `900` Sekunden
|
|
|
|
|
- Block: `900` Sekunden
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
2026-02-24 08:49:40 +01:00
|
|
|
### API-Login (`/api/v1/auth/login`)
|
|
|
|
|
|
|
|
|
|
Zusätzlich zum allgemeinen API-Limit in `ApiBootstrap` gelten eigene Login-Limits:
|
|
|
|
|
|
|
|
|
|
1. Schritt `login_ip` (IP)
|
|
|
|
|
- Scope: `api.auth.login.ip`
|
|
|
|
|
- Key: `<ip>`
|
|
|
|
|
- Limit: `10` Fehlversuche pro `600` Sekunden
|
|
|
|
|
- Block: `300` Sekunden
|
|
|
|
|
|
|
|
|
|
2. Schritt `login_email_ip` (email + ip)
|
|
|
|
|
- Scope: `api.auth.login.email_ip`
|
|
|
|
|
- Key: `<lowercase-email>|<ip>`
|
|
|
|
|
- Limit: `5` Fehlversuche pro `900` Sekunden
|
|
|
|
|
- Block: `900` Sekunden
|
|
|
|
|
|
|
|
|
|
Verhalten:
|
|
|
|
|
- Endpoint bleibt public (kein Bearer erforderlich).
|
|
|
|
|
- Bei Block: HTTP `429` + `Retry-After`.
|
|
|
|
|
- Bei erfolgreichem API-Login wird `api.auth.login.email_ip` für den Key zurückgesetzt.
|
|
|
|
|
|
add composer-unused, comprehensive docs, and project restructure
- 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>
2026-02-22 15:27:35 +01:00
|
|
|
## Datenfluss pro Request
|
|
|
|
|
|
|
|
|
|
1. Key bilden (`scope` + Subject)
|
|
|
|
|
2. Subject hashen (`sha256`)
|
|
|
|
|
3. Bestehenden Datensatz lesen
|
|
|
|
|
4. Falls `blocked_until > now`: direkt blocken
|
|
|
|
|
5. Fenster prüfen (`window_started_at + windowSeconds`)
|
|
|
|
|
6. Hits erhöhen
|
|
|
|
|
7. Bei `hits > max`: `blocked_until = now + blockSeconds`
|
|
|
|
|
8. 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:
|
|
|
|
|
1. Schnell >120 Requests/min ohne Bearer gegen `/api/v1/*`
|
|
|
|
|
2. Erwartung: `429` mit `Retry-After`
|
|
|
|
|
|
|
|
|
|
Login:
|
|
|
|
|
1. Mehrere falsche Passwortversuche für dieselbe Email+IP
|
|
|
|
|
2. Erwartung nach 5 Fehlversuchen: `429` und 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).
|