Aktuelle Lage: PHP2Shell. Zwei kritische PHP-Lücken (CVSS 9.2) erlauben Schadcode ohne Anmeldung. Patches seit 21.10.2026.Was jetzt zu tun ist →

CSRF-Schutz in PHP-Anwendungen

Wie Entwickler Cross-Site Request Forgery in PHP-Anwendungen verhindern: Tokens für jede verändernde Anfrage, Herkunftsprüfung im Header und SameSite-Cookies als zusätzliche Schicht.

Stand 5 Min. LesezeitSichere Entwicklung

Kurz gesagt: CSRF in PHP verhindern Sie, indem jede Anfrage, die etwas verändert, ein geheimes, an die Session gebundenes Token mitbringen muss, das Sie serverseitig mit hash_equals() prüfen. Zusätzlich prüfen Sie die Header Origin oder Sec-Fetch-Site und setzen Session-Cookies mit SameSite. GET-Anfragen dürfen nie Daten verändern, und das Login-Formular braucht ebenfalls Schutz.

Ein Klick, den niemand bemerkt

Eine Mitarbeiterin ist im Shop-Backend angemeldet und öffnet in einem zweiten Tab eine fremde Seite. Diese Seite schickt im Hintergrund ein Formular an das Backend, etwa zum Ändern einer E-Mail-Adresse oder zum Anlegen eines Kontos. Der Browser hängt das Session-Cookie automatisch an. Für die Anwendung sieht die Anfrage aus wie jede andere aus dem eigenen Team.

Das ist Cross-Site Request Forgery, kurz CSRF: eine Anfrage, die ein angemeldeter Nutzer unwissentlich an eine Anwendung sendet, der er vertraut. Der Angreifer sieht die Antwort nicht, aber er braucht sie auch nicht. Es reicht, dass die Aktion ausgeführt wird.

CSRF steht nicht in den Schlagzeilen wie PHP2Shell, ist aber in selbst entwickelten PHP-Anwendungen ein häufiger Befund. Frameworks wie Symfony und Laravel bringen einen Schutz mit; Lücken entstehen dort vor allem, wo er für einzelne Routen abgeschaltet wurde. Eigenentwicklungen ohne Framework haben oft gar keinen.

CSRF in PHP: Welche Anfragen geschützt werden müssen

Schutz brauchen alle Anfragen, die einen Zustand verändern: Speichern, Löschen, Bestellen, Rechte vergeben, Einstellungen ändern, Dateien hochladen, Abmelden. Lesende Aufrufe brauchen keinen Token, solange sie wirklich nur lesen.

Daraus folgt die erste Regel: Keine Änderung per GET. Links wie loeschen.php?id=… lassen sich von fremden Seiten besonders leicht auslösen, etwa über ein eingebettetes Bild. Verändernde Aktionen gehören in POST, PUT, PATCH oder DELETE.

Die zweite Regel: Auch die Anmeldung schützen. Beim sogenannten Login-CSRF wird ein Opfer unbemerkt in ein Konto des Angreifers eingeloggt. Gibt es dort Zahlungsdaten oder Dokumente ein, landen diese beim Angreifer. Ein Token im Login-Formular und eine neue Session-ID nach erfolgreicher Anmeldung verhindern das.

Das Synchronizer-Token-Muster in PHP

Für klassische Anwendungen mit Sessions empfiehlt OWASP das Synchronizer-Token-Muster: Der Server erzeugt ein zufälliges Token, speichert es in der Session und erwartet es in jedem verändernden Formular zurück. Wichtig ist, dass das Token im Formular oder in einem eigenen Header mitgesendet wird, nicht in einem Cookie.

<?php
declare(strict_types=1);

function csrfToken(): string
{
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

function csrfPruefen(): void
{
    $gesendet = $_POST['csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
    if (!is_string($gesendet) || !hash_equals(csrfToken(), $gesendet)) {
        http_response_code(403);
        exit('Anfrage abgelehnt.');
    }
}

if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
    csrfPruefen();
}
?>
<form method="post" action="/konto/email">
    <input type="hidden" name="csrf_token"
           value="<?= htmlspecialchars(csrfToken(), ENT_QUOTES, 'UTF-8') ?>">
    <!-- weitere Felder -->
</form>

hash_equals() vergleicht in konstanter Zeit, sodass die Antwortzeit nichts über den richtigen Wert verrät. Nach dem Login sollten Sie die Session-ID mit session_regenerate_id(true) erneuern und ein neues Token erzeugen. Warum random_bytes() die richtige Quelle ist und welche Funktionen ungeeignet sind, erklärt Sichere Zufallszahlen und Tokens in PHP.

Ein Token pro Session genügt für die meisten Anwendungen. Tokens pro Formular oder pro Anfrage erhöhen den Schutz etwas, führen aber zu Problemen mit mehreren offenen Tabs und dem Zurück-Knopf. Wichtiger als die Häufigkeit des Wechsels ist, dass das Token nie in URLs auftaucht, wo es in Logs, im Browserverlauf und in Referrer-Angaben an fremde Seiten landen kann.

Für zustandslose Anwendungen ohne Session nennt OWASP als Alternative das signierte Double-Submit-Cookie: ein Token, das per HMAC an die Sitzung gebunden ist. Die einfache, unsignierte Variante wird ausdrücklich nicht empfohlen.

Zweite Schicht: Origin, Sec-Fetch-Site und SameSite

Moderne Browser senden bei Anfragen Informationen über ihre Herkunft. Der Header Origin nennt die aufrufende Seite, Sec-Fetch-Site sagt, ob die Anfrage von derselben Seite (same-origin), einer verwandten (same-site) oder einer fremden (cross-site) stammt. Daraus lässt sich eine einfache Zusatzprüfung bauen:

<?php
$erlaubteHerkunft = 'https://www.example.de';
$fetchSite = $_SERVER['HTTP_SEC_FETCH_SITE'] ?? null;
$origin    = $_SERVER['HTTP_ORIGIN'] ?? null;

$verdaechtig = ($fetchSite !== null && $fetchSite !== 'same-origin')
    || ($fetchSite === null && $origin !== null && $origin !== $erlaubteHerkunft);

if ($_SERVER['REQUEST_METHOD'] !== 'GET' && $verdaechtig) {
    http_response_code(403);
    exit;
}

OWASP betont dabei zwei Punkte: Die Herkunft muss vollständig verglichen werden, damit ähnlich klingende Domains nicht durchrutschen, und ein fehlender Header oder der Wert null darf nicht als eigene Herkunft gelten. Weil ältere Browser die Header nicht immer senden, bleibt das Token die Hauptverteidigung.

Die dritte Schicht sind Session-Cookies mit SameSite. PHP unterstützt session.cookie_samesite seit Version 7.3, der Standardwert ist leer. Setzen Sie mindestens Lax, für reine Backends ist Strict oft möglich. Die übrigen Cookie-Einstellungen beschreibt der Ratgeber Sessions in PHP absichern.

Nutzen Sie ein CMS, bringt es meist eigene Werkzeuge mit. WordPress etwa arbeitet mit sogenannten Nonces, die Plugins über Funktionen wie wp_nonce_field() und check_admin_referer() einbinden. Lücken entstehen in der Praxis vor allem in Erweiterungen, die solche Prüfungen bei einzelnen Aktionen vergessen. Prüfen Sie deshalb besonders selbst geschriebene oder wenig verbreitete Plugins.

Bei Schnittstellen, die Browser von anderen Domains aus nutzen, entscheidet zusätzlich die CORS-Konfiguration. Gibt der Server jede anfragende Herkunft als erlaubt zurück und lässt zugleich Cookies zu, hebelt er den Schutz des Browsers selbst aus. OWASP empfiehlt, CORS nur für ausdrücklich vertrauenswürdige Herkünfte zu öffnen; eine pauschale Freigabe aller Subdomains wird zum Problem, sobald eine davon in fremde Hände gerät.

Prüfliste für bestehende Anwendungen

Bei gewachsenen Projekten hilft eine systematische Durchsicht:

  1. Alle Routen und Skripte erfassen, die Daten verändern, auch Ajax-Endpunkte und Datei-Uploads.
  2. Prüfen, ob dafür GET verwendet wird, und auf POST oder passende Methoden umstellen.
  3. Für jede verändernde Route nachweisen, dass ein Token geprüft wird; Ausnahmen im Framework gezielt suchen.
  4. Login, Abmeldung und Passwortänderung gesondert testen.
  5. session.cookie_samesite und die Herkunftsprüfung ergänzen.
  6. XSS-Lücken beheben, denn eingeschleuster Code kann jedes Token lesen. Das Vorgehen beschreibt Cross-Site-Scripting in PHP verhindern.
Wichtig

Ein CSRF-Schutz, der nur im Frontend per JavaScript geprüft wird, ist wirkungslos. Die Prüfung muss auf dem Server stattfinden, bevor die Aktion ausgeführt wird.

Wie hilft PHP SOS konkret?

  • Wir erfassen alle verändernden Routen Ihrer PHP-Anwendung und prüfen, wo ein Token fehlt oder abgeschaltet wurde.
  • Wir bauen einen zentralen Prüfpunkt ein, statt Token-Prüfungen über viele Skripte zu verteilen.
  • Wir ergänzen Herkunftsprüfung und SameSite-Einstellungen, ohne Zahlungs- oder Login-Abläufe zu stören.
  • Wir testen nach der Umstellung erneut und dokumentieren die Ergebnisse.

Eine vollständige Prüfung Ihrer Anwendung beschreibt die Leistung Sicherheitsaudit und Penetrationstest.

Häufige Fragen

Reicht SameSite=Lax als CSRF-Schutz?

Nein. SameSite-Cookies sind laut OWASP eine zusätzliche Schicht, kein Ersatz. Lax sendet Cookies weiterhin bei normalen Seitenaufrufen per GET, und Angriffe von Subdomains derselben Website werden nicht abgedeckt.

Brauchen JSON-APIs ein CSRF-Token?

Wenn die API mit Cookies authentifiziert, ja oder eine gleichwertige Prüfung. Eine Alternative sind eigene Anfrage-Header, die Browser bei fremden Seiten nur nach einer CORS-Vorabprüfung erlauben. Dann darf die CORS-Freigabe aber nur ausdrücklich vertrauenswürdige Herkünfte enthalten.

Muss auch das Login-Formular geschützt werden?

Ja. Bei Login-CSRF wird ein Opfer unbemerkt in ein fremdes Konto eingeloggt und gibt dort eigene Daten ein. Ein Token im Login-Formular und eine neue Session nach der Anmeldung verhindern das.

Schützt CSRF-Schutz auch vor XSS?

Umgekehrt: Eine XSS-Lücke hebelt jeden CSRF-Schutz aus, weil eingeschleuster Code im Namen der Seite gültige Tokens lesen und mitsenden kann. Beide Schwachstellen müssen getrennt behoben werden.

Quellen

Sofort-Kontakt

Jede Stunde zählt. Schreiben Sie uns jetzt.

Schildern Sie kurz System, PHP-Version und Beobachtung. Wir melden uns, klären die Lage und arbeiten remote, bis der Vorfall abgeschlossen und dokumentiert ist.

Sofort-Hilfe