# CSRF-Schutz > **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung des CSRF-Schutzes korrekt dar. ## Übersicht Cross-Site Request Forgery (CSRF) ist eine Art von Angriff, bei dem ein Angreifer einen Benutzer dazu bringt, unbeabsichtigt Aktionen auf einer Website auszuführen, bei der er bereits authentifiziert ist. Das Framework bietet einen robusten CSRF-Schutzmechanismus, der solche Angriffe verhindert, indem es einzigartige Token generiert und validiert. ## Hauptkomponenten ### CsrfToken Die `CsrfToken`-Klasse ist ein Value Object, das einen CSRF-Token repräsentiert: ```php use App\Framework\Security\CsrfToken; // Token aus einem String erstellen $token = CsrfToken::fromString($tokenString); // Token-Wert als String abrufen $tokenString = $token->toString(); // oder $tokenString = (string)$token; ``` Die Klasse stellt sicher, dass CSRF-Token immer gültige 64-Zeichen lange hexadezimale Strings sind und bietet Typsicherheit für CSRF-Token-Operationen. ### CsrfTokenGenerator Die `CsrfTokenGenerator`-Klasse ist verantwortlich für die Generierung neuer CSRF-Token: ```php use App\Framework\Security\CsrfTokenGenerator; // Generator initialisieren $generator = new CsrfTokenGenerator($randomGenerator); // Neues Token generieren $token = $generator->generate(); ``` Die Klasse verwendet einen kryptografisch sicheren Zufallszahlengenerator, um Token zu erzeugen, die nicht vorhersehbar sind. ### CsrfTokenData Die `CsrfTokenData`-Klasse erweitert das einfache Token um zusätzliche Metadaten: ```php use App\Framework\Security\CsrfTokenData; // Token-Daten mit Metadaten erstellen $tokenData = new CsrfTokenData( $token, $clientIp, $targetPath, $expiresAt ); // Prüfen, ob das Token abgelaufen ist if ($tokenData->isExpired($clock)) { // Token ist abgelaufen } // Prüfen, ob das Token bereits verwendet wurde if ($tokenData->isUsed()) { // Token wurde bereits verwendet } ``` Diese Klasse ermöglicht erweiterte Sicherheitsfunktionen wie Token-Ablauf, Verwendungsverfolgung und Bindung an bestimmte Pfade oder IP-Adressen. ## Verwendung ### Token generieren und in Formularen verwenden ```php // In einem Controller public function showForm(): Response { // Token generieren $csrfToken = $this->csrfTokenGenerator->generate(); // Token in der Session speichern $this->session->set('csrf_token', $csrfToken->toString()); // Token im Formular einbinden return $this->render('form.twig', [ 'csrf_token' => $csrfToken->toString(), ]); } ``` In der Formularvorlage: ```html
``` ### Token validieren ```php // In einem Controller public function handleForm(Request $request): Response { // Gespeichertes Token abrufen $storedToken = CsrfToken::fromString($this->session->get('csrf_token')); // Übermitteltes Token abrufen $submittedToken = $request->getPostParam('csrf_token'); // Token vergleichen (zeitsichere Vergleichsmethode) if (!$storedToken->equalsString($submittedToken)) { throw new SecurityException('Ungültiges CSRF-Token'); } // Token ist gültig, Formular verarbeiten // ... } ``` ### Erweiterte Token-Validierung mit Metadaten ```php // In einem Controller public function showForm(): Response { // Token mit Metadaten generieren $token = $this->csrfTokenGenerator->generate(); $tokenData = new CsrfTokenData( $token, $this->request->getClientIp(), $this->request->path, new \DateTimeImmutable('+1 hour') ); // Token-Daten in der Session speichern $this->session->set('csrf_token_data', $tokenData->toArray()); // Token im Formular einbinden return $this->render('form.twig', [ 'csrf_token' => $token->toString(), ]); } public function handleForm(Request $request): Response { // Token-Daten aus der Session abrufen $tokenDataArray = $this->session->get('csrf_token_data'); $tokenData = CsrfTokenData::fromArray($tokenDataArray); // Übermitteltes Token abrufen $submittedToken = $request->getPostParam('csrf_token'); // Umfassende Validierung durchführen if ($tokenData->isExpired($this->clock)) { throw new SecurityException('CSRF-Token ist abgelaufen'); } if ($tokenData->isUsed()) { throw new SecurityException('CSRF-Token wurde bereits verwendet'); } if ($tokenData->clientIp !== $request->getClientIp()) { throw new SecurityException('CSRF-Token ist an eine andere IP-Adresse gebunden'); } if (!$tokenData->token->equalsString($submittedToken)) { throw new SecurityException('Ungültiges CSRF-Token'); } // Token als verwendet markieren $tokenData->markAsUsed(); $this->session->set('csrf_token_data', $tokenData->toArray()); // Token ist gültig, Formular verarbeiten // ... } ``` ## Integration mit dem Framework ### CSRF-Middleware Das Framework bietet eine `CsrfProtectionMiddleware`, die automatisch CSRF-Schutz für alle POST, PUT, DELETE und PATCH-Anfragen implementiert: ```php // In der Bootstrap-Datei oder Router-Konfiguration $app->addMiddleware(CsrfProtectionMiddleware::class); ``` Die Middleware: 1. Generiert automatisch CSRF-Token für alle Formulare 2. Validiert Token für alle Anfragen, die den Zustand ändern 3. Wirft eine Exception oder gibt eine Fehlerantwort zurück, wenn die Validierung fehlschlägt ### Konfiguration Die CSRF-Schutzfunktionen können in der Konfigurationsdatei angepasst werden: ```php // config/security.php return [ 'csrf' => [ 'enabled' => true, 'token_lifetime' => 3600, // Sekunden 'exclude_routes' => [ '/api/webhook', '/api/external/callback', ], 'exclude_patterns' => [ '#^/api/public/#', // Regulärer Ausdruck für auszuschließende Routen ], 'header_name' => 'X-CSRF-Token', // Name des HTTP-Headers für API-Anfragen 'parameter_name' => 'csrf_token', // Name des Formularfelds 'strict_mode' => true, // Strikte Validierung (IP-Bindung, Einmalverwendung) ], ]; ``` ### Template-Integration Das Framework bietet eine einfache Möglichkeit, CSRF-Token in Templates einzubinden: ```php // In einem Controller public function showForm(): Response { return $this->render('form.twig', [ 'csrf_token' => $this->csrfProtection->getToken()->toString(), ]); } ``` Mit der Template-Funktion: ```twig {# In einer Twig-Vorlage #}
{{ csrf_field() }}
``` Die `csrf_field()`-Funktion generiert automatisch ein verstecktes Formularfeld mit dem aktuellen CSRF-Token. ### API-Integration Für API-Anfragen kann das CSRF-Token über einen HTTP-Header übermittelt werden: ```javascript // JavaScript-Beispiel fetch('/api/data', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content }, body: JSON.stringify(data) }); ``` In der HTML-Vorlage: ```html ``` ## Erweiterte Funktionen ### Double Submit Cookie Pattern Das Framework unterstützt das Double Submit Cookie Pattern für zusätzliche Sicherheit: ```php // In einem Controller public function showForm(): Response { $token = $this->csrfTokenGenerator->generate(); // Token in der Session speichern $this->session->set('csrf_token', $token->toString()); // Token auch als Cookie setzen $this->response->setCookie('csrf_token', $token->toString(), [ 'httponly' => false, // JavaScript muss darauf zugreifen können 'samesite' => 'Strict', 'secure' => true, 'path' => '/', ]); return $this->render('form.twig', [ 'csrf_token' => $token->toString(), ]); } ``` ### Token-Rotation Für zusätzliche Sicherheit können CSRF-Token nach jeder Anfrage rotiert werden: ```php // In einem Controller public function handleForm(Request $request): Response { // Token validieren // ... // Neues Token generieren $newToken = $this->csrfTokenGenerator->generate(); $this->session->set('csrf_token', $newToken->toString()); // Antwort mit neuem Token return $this->render('success.twig', [ 'new_csrf_token' => $newToken->toString(), ]); } ``` ### Synchronizer Token Pattern Das Framework implementiert das Synchronizer Token Pattern, bei dem für jede Sitzung ein eindeutiges Token generiert wird: ```php // In der Session-Initialisierung public function initializeSession(): void { if (!$this->session->has('csrf_token')) { $token = $this->csrfTokenGenerator->generate(); $this->session->set('csrf_token', $token->toString()); } } ``` ## Fehlerbehebung ### Häufige Probleme #### Token-Validierung schlägt fehl Mögliche Ursachen: - Das Token ist abgelaufen - Das Token wurde bereits verwendet - Das Token wurde nicht korrekt übermittelt - Die Session ist abgelaufen oder wurde zurückgesetzt Lösung: - Überprüfen Sie die Session-Konfiguration - Stellen Sie sicher, dass das Token korrekt im Formular eingebunden ist - Erhöhen Sie die Token-Lebensdauer in der Konfiguration #### CSRF-Schutz für bestimmte Routen deaktivieren Wenn Sie den CSRF-Schutz für bestimmte Routen deaktivieren müssen (z.B. für Webhook-Callbacks): ```php // config/security.php return [ 'csrf' => [ 'exclude_routes' => [ '/api/webhook', '/api/external/callback', ], ], ]; ``` #### AJAX-Anfragen mit CSRF-Schutz Für AJAX-Anfragen müssen Sie das CSRF-Token im Header oder als Formularfeld übermitteln: ```javascript // JavaScript mit jQuery $.ajaxSetup({ headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') } }); // Oder mit Fetch API fetch('/api/data', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content }, body: JSON.stringify(data) }); ``` ## Sicherheitsüberlegungen ### Best Practices 1. **Verwenden Sie HTTPS**: CSRF-Token sollten immer über eine verschlüsselte Verbindung übertragen werden. 2. **Kurze Token-Lebensdauer**: Setzen Sie die Token-Lebensdauer auf einen angemessenen Wert (z.B. 1-2 Stunden). 3. **Strikte SameSite-Cookie-Einstellungen**: Verwenden Sie `SameSite=Strict` oder `SameSite=Lax` für Session-Cookies. 4. **Token-Rotation**: Rotieren Sie Token nach jeder Anfrage, die den Zustand ändert. 5. **Validieren Sie alle Anfragen**: Stellen Sie sicher, dass alle Anfragen, die den Zustand ändern, ein gültiges CSRF-Token erfordern. ### Bekannte Einschränkungen - CSRF-Schutz funktioniert nicht für Benutzer, die keine Cookies akzeptieren. - Bei sehr langen Sitzungen kann die Sicherheit des CSRF-Tokens beeinträchtigt sein. - CSRF-Schutz kann mit bestimmten Caching-Strategien in Konflikt geraten. ## Weiterführende Informationen - [Security Features Übersicht](index.md) - [Security Headers und CSP](security-headers.md) - [Request Signing API](request-signing.md) - [Sicherheits-Best-Practices](/guides/security-best-practices.md)