Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

CSRF-Schutz und Formular-Sicherheit

CSRF-Schutz und Formular-Sicherheit

~13 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026

Zum Abschluss von Block 3 verstehen wir eine Sicherheitsfunktion, die wir bereits UNBEMERKT bei jedem {{ form(form) }}-Aufruf genutzt haben: CSRF-Schutz.

Was ist ein CSRF-Angriff?

Cross-Site Request Forgery: eine BÖSARTIGE, fremde Webseite bringt den Browser eines eingeloggten Nutzers dazu, unbemerkt eine Anfrage an UNSERE Anwendung zu senden – z. B. ein verstecktes Formular, das automatisch POST /projects/1/delete auf unserem Aufgaben-Manager auslöst, während der Nutzer eine völlig andere Seite besucht. Da der Browser AUTOMATISCH gültige Session-Cookies mitsendet, sähe diese Anfrage für unseren Server "legitim" aus.

Wie Symfonys CSRF-Schutz funktioniert

Symfony Forms fügen AUTOMATISCH ein verstecktes _token-Feld mit einem session-gebundenen, kryptografisch zufälligen Wert ein – GENAU DIESEN Token kann eine fremde Seite NICHT kennen, da er weder in der URL noch für JavaScript auf einer anderen Domain zugänglich ist. Fehlt der Token oder stimmt er nicht, weist Symfony die Anfrage VOR jeder weiteren Verarbeitung ab.

Das Beste daran: DAS PASSIERT AUTOMATISCH. createForm() (Kapitel 15) fügt den Token ein, handleRequest() prüft ihn – wir haben seit Kapitel 15, ohne es zu wissen, bereits CSRF-Schutz für JEDES unserer Formulare.

Den Token sichtbar machen

Rendern Sie ein Formular und öffnen Sie den Quelltext im Browser – Sie finden ein Feld wie:

<input type="hidden" id="project__token" name="project[_token]" value="a1b2c3...">

CSRF-Schutz OHNE Symfony Forms

Manche Aktionen (z. B. ein "Löschen"-Button, der KEIN vollständiges Formular mit Textfeldern braucht) nutzen Symfony Forms oft NICHT – trotzdem verdienen sie CSRF-Schutz. Manuell mit dem csrf_token()-Helfer:

<form method="post" action="{{ path('project_delete', {id: projekt.id}) }}">
    <input type="hidden" name="_token" value="{{ csrf_token('delete-projekt-' ~ projekt.id) }}">
    <button type="submit">Löschen</button>
</form>
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Csrf\CsrfToken;

#[Route('/projects/{id}/delete', name: 'project_delete', methods: ['POST'])]
public function delete(int $id, Request $request, CsrfTokenManagerInterface $csrfTokenManager): Response
{
    $token = new CsrfToken('delete-projekt-' . $id, $request->request->get('_token'));

    if (!$csrfTokenManager->isTokenValid($token)) {
        throw $this->createAccessDeniedException('Ungültiger CSRF-Token.');
    }

    // Projekt löschen (Block 4)
    return $this->redirectToRoute('project_index');
}

Der String 'delete-projekt-' . $id ist die "Token-ID" – bewusst EINDEUTIG pro Projekt gewählt, damit ein für Projekt 1 generierter Token nicht für die Löschung von Projekt 2 wiederverwendet werden kann.

methods: ['GET'] ist ebenfalls ein Sicherheitsprinzip

Achtung: Erinnerung an Kapitel 7/9: zustandsändernde Aktionen (Erstellen, Ändern, Löschen) sollten NIEMALS über GET-Routen erreichbar sein – GET-Anfragen werden von Browsern, Crawlern und Proxies oft VORAB geladen oder wiederholt ("Prefetching"), was bei einer GET-basierten Löschroute zu VERSEHENTLICHEN Löschungen führen könnte, ganz ohne bösartige Absicht. methods: ['POST'] für JEDE Aktion mit Seiteneffekten ist keine Stilfrage, sondern ein Sicherheitsprinzip.

Damit ist Block 3 (Twig & Formulare) abgeschlossen! Unser Aufgaben-Manager hat jetzt echte, sicher validierte, CSRF-geschützte Formulare – Block 4 fügt endlich eine ECHTE Datenbank hinzu, damit die eingegebenen Daten auch dauerhaft erhalten bleiben.