# CSRF Protection System ## Übersicht Das CSRF (Cross-Site Request Forgery) Protection System bietet robusten Schutz gegen CSRF-Angriffe durch: - **Atomare Session-Updates**: Verhindert Race Conditions bei parallelen Requests - **Vereinfachte Token-Generierung**: Immer neue Token, keine Wiederverwendung - **Robuste HTML-Verarbeitung**: DOM-basierte Token-Ersetzung mit Regex-Fallback - **Einheitliche API**: Konsistente Endpunkte für PHP und JavaScript ## Architektur ### Komponenten 1. **CsrfProtection**: Verwaltet Token-Generierung und Validierung 2. **SessionManager**: Bietet atomare Session-Updates mit Locking 3. **FormDataResponseProcessor**: Ersetzt Token-Platzhalter in HTML 4. **CsrfMiddleware**: Validiert Token bei state-changing Requests 5. **API Controllers**: Bereitstellen Token-Endpunkte für JavaScript ### Session-Locking Das System verwendet Session-Locking, um Race Conditions zu verhindern: - **FileSessionStorage**: Datei-basiertes Locking mit `flock()` - **RedisSessionStorage**: Redis `SET NX EX` für atomares Locking - **InMemorySessionStorage**: In-Memory-Locking für Tests ### Optimistic Locking SessionData verwendet Versionsnummern für Optimistic Locking: - Jede Änderung inkrementiert die Version - Bei Konflikten wird automatisch retried - Verhindert Datenverlust bei parallelen Updates ## Token-Generierung ### Vereinfachte Strategie **Wichtig**: Das System generiert **immer neue Token** - keine Wiederverwendung. ```php // Generiert immer einen neuen Token $token = $session->csrf->generateToken($formId); ``` ### Token-Verwaltung - **Maximal 3 Token pro Form-ID**: Älteste werden automatisch entfernt - **Token-Lifetime**: 2 Stunden (7200 Sekunden) - **Re-Submit Window**: 30 Sekunden für erneute Submissions - **Automatisches Cleanup**: Abgelaufene Token werden entfernt ### Token-Format - **Länge**: 64 Zeichen - **Format**: Hexadezimal (0-9, a-f) - **Beispiel**: `f677a410facd19e4e004e41e24fa1c8abbe2379a91abcf8642de23a6988ba8b` ## HTML-Verarbeitung ### DOM-basierte Ersetzung Der `FormDataResponseProcessor` verwendet DOM-basierte Verarbeitung für robuste Token-Ersetzung: ```php // Automatische Ersetzung von Platzhaltern $html = $processor->process($html, $session); ``` ### Platzhalter-Format ```html ``` ### Fallback-Mechanismus Bei DOM-Parsing-Fehlern fällt das System automatisch auf Regex-basierte Ersetzung zurück. ## API-Endpunkte ### Token-Generierung **GET/POST `/api/csrf/token`** Generiert einen neuen CSRF-Token für eine Form. **Parameter:** - `action` (optional): Form-Action URL (Standard: `/`) - `method` (optional): HTTP-Methode (Standard: `post`) - `form_id` (optional): Explizite Form-ID **Response:** ```json { "form_id": "form_abc123def456", "token": "64-character-hex-token", "expires_in": 7200, "headers": { "X-CSRF-Form-ID": "form_abc123def456", "X-CSRF-Token": "64-character-hex-token" } } ``` ### Token-Refresh **GET `/api/csrf/refresh`** Generiert einen neuen Token für eine bestehende Form-ID. **Parameter:** - `form_id` (erforderlich): Form-ID **Response:** ```json { "form_id": "form_abc123def456", "token": "64-character-hex-token", "expires_in": 7200, "headers": { "X-CSRF-Form-ID": "form_abc123def456", "X-CSRF-Token": "64-character-hex-token" } } ``` ### Token-Informationen **GET `/api/csrf/info`** Gibt Informationen über aktive Token zurück. **Parameter:** - `form_id` (erforderlich): Form-ID **Response:** ```json { "form_id": "form_abc123def456", "active_tokens": 2, "max_tokens_per_form": 3, "token_lifetime_seconds": 7200, "resubmit_window_seconds": 30 } ``` ## JavaScript-Integration ### CsrfManager Der `CsrfManager` verwaltet Token automatisch: ```javascript import { CsrfManager } from './modules/security/CsrfManager.js'; const csrfManager = CsrfManager.create({ endpoint: '/api/csrf/token', autoRefresh: true, refreshInterval: 30 * 60 * 1000 // 30 Minuten }); // Token abrufen const token = csrfManager.getToken(); // Token-Header für Requests const headers = csrfManager.getTokenHeader(); ``` ### Manuelle Token-Anfrage ```javascript // Token für spezifische Form generieren const response = await fetch('/api/csrf/token?action=/submit&method=post'); const data = await response.json(); const token = data.token; const formId = data.form_id; ``` ### AJAX-Requests ```javascript // Token in Request-Body fetch('/api/submit', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Form-ID': formId, 'X-CSRF-Token': token }, body: JSON.stringify({ _form_id: formId, _token: token, // ... weitere Daten }) }); ``` ## Validierung ### Middleware Die `CsrfMiddleware` validiert automatisch Token für: - POST Requests - PUT Requests - DELETE Requests - PATCH Requests GET Requests werden nicht validiert. ### Validierungsprozess 1. **Token-Extraktion**: Aus Request-Body oder Headers 2. **Form-ID-Extraktion**: Aus Request-Body oder Headers 3. **Session-Lookup**: Token in Session suchen 4. **Validierung**: Token-Match und Expiration prüfen 5. **Markierung**: Token als verwendet markieren ### Fehlerbehandlung Bei Validierungsfehlern wird eine `CsrfValidationFailedException` geworfen mit: - Fehlgrund (missing token, invalid token, expired, etc.) - Session-ID - Anzahl verfügbarer Token - Liste verfügbarer Form-IDs ## Best Practices ### Form-IDs - Verwende konsistente Form-IDs für dieselben Formulare - Form-IDs werden automatisch aus Action und Method generiert - Explizite Form-IDs können über `form_id` Parameter gesetzt werden ### Token-Refresh - Token sollten vor Ablauf erneuert werden - Automatischer Refresh alle 30 Minuten empfohlen - Bei langen Formularen manuell vor Submit refreshen ### Fehlerbehandlung ```php try { // Form-Verarbeitung } catch (CsrfValidationFailedException $e) { // Token ungültig - Benutzer sollte Seite neu laden return redirect()->back()->with('error', 'Session expired. Please try again.'); } ``` ### Testing ```php // Token generieren $token = $session->csrf->generateToken('test-form'); // Token validieren $isValid = $session->csrf->validateToken('test-form', $token); // Mit Debug-Informationen $result = $session->csrf->validateTokenWithDebug('test-form', $token); if (!$result['valid']) { $reason = $result['debug']['reason']; // ... } ``` ## Troubleshooting ### Token wird nicht akzeptiert 1. **Prüfe Token-Länge**: Muss genau 64 Zeichen sein 2. **Prüfe Form-ID**: Muss mit generierter Form-ID übereinstimmen 3. **Prüfe Session**: Token muss in Session vorhanden sein 4. **Prüfe Expiration**: Token darf nicht abgelaufen sein ### Race Conditions Das System verwendet atomare Session-Updates, um Race Conditions zu verhindern. Bei Problemen: 1. Prüfe Session-Storage-Konfiguration 2. Prüfe Locking-Mechanismus (File/Redis) 3. Prüfe Logs für Version-Conflicts ### HTML-Verarbeitung Bei Problemen mit Token-Ersetzung: 1. Prüfe Platzhalter-Format: `___TOKEN_FORMID___` 2. Prüfe HTML-Struktur (DOM-Parsing kann bei malformed HTML fehlschlagen) 3. Prüfe Logs für Fallback auf Regex ## Migration ### Von altem System Das neue System ist vollständig kompatibel mit dem alten System: - Alte Token werden weiterhin akzeptiert - Alte API-Endpunkte funktionieren weiterhin - Keine Breaking Changes ### Neue Features nutzen 1. Verwende `/api/csrf/token` statt `/api/csrf-token` 2. Nutze atomare Session-Updates für kritische Operationen 3. Verwende DOM-basierte HTML-Verarbeitung (automatisch) ## Performance ### Optimierungen - **Token-Cleanup**: Automatisch nach 5 Minuten - **Maximal 3 Token**: Begrenzt Session-Größe - **Locking-Timeout**: 5 Sekunden Standard-Timeout - **Optimistic Locking**: Reduziert Lock-Contention ### Monitoring - Token-Anzahl pro Form-ID überwachen - Session-Lock-Contention überwachen - Token-Validierungs-Fehlerrate überwachen ## Sicherheit ### Schutz-Mechanismen 1. **Token-Rotation**: Neue Token nach jeder Generierung 2. **Expiration**: Token laufen nach 2 Stunden ab 3. **Single-Use**: Token können innerhalb von 30 Sekunden wiederverwendet werden 4. **Session-Binding**: Token sind an Session gebunden ### Angriffs-Vektoren Das System schützt gegen: - **CSRF-Angriffe**: Token-Validierung verhindert unautorisierte Requests - **Token-Replay**: Expiration und Single-Use verhindern Replay - **Session-Hijacking**: Session-Binding verhindert Token-Diebstahl ## Referenz ### Klassen - `App\Framework\Http\Session\CsrfProtection` - `App\Framework\Http\Session\SessionManager` - `App\Framework\View\Response\FormDataResponseProcessor` - `App\Framework\Http\Middlewares\CsrfMiddleware` - `App\Application\Api\CsrfController` - `App\Application\Controller\CsrfController` ### Konstanten - `CsrfProtection::TOKEN_LIFETIME` = 7200 (2 Stunden) - `CsrfProtection::MAX_TOKENS_PER_FORM` = 3 - `CsrfProtection::RE_SUBMIT_WINDOW` = 30 (Sekunden)