MB Dev .tech
Registrieren Login

Sicherheit Basics · CSRF & Tokens

← Zurück zu Sicherheit Basics

CSRF steht für Cross-Site Request Forgery. Das ist ein Angriff, bei dem ein Browser (unbemerkt) einen Request an deine Seite sendet, während der Nutzer dort eingeloggt ist.

Merke
Bei CSRF „missbraucht“ der Angreifer den Login-Zustand

Der Nutzer ist echt – aber der Klick/Request kommt nicht von ihm, sondern wird ausgelöst. Schutz dagegen: CSRF-Tokens.

1) Was passiert bei CSRF?

Stell dir vor, du hast in deiner Anwendung eine Funktion: „E-Mail-Adresse ändern“. Der Nutzer ist eingeloggt, also schickt der Browser automatisch seine Session-Cookies mit.

Jetzt kommt der Trick: Wenn der Nutzer eine fremde Webseite besucht, kann diese Webseite versuchen, einen Request an deine Seite auszulösen. Der Browser schickt dabei (unter Umständen) automatisch die Cookies mit – weil es „für den Browser“ ganz normal aussieht.

Achtung
Cookies werden automatisch mitgesendet

Genau deshalb ist CSRF möglich: Der Browser hängt die Session an – egal, ob der Klick „gewollt“ war.

2) Warum du Änderungen nie per GET machen solltest

Wenn du Zustände änderst (z.B. „löschen“, „ändern“, „kaufen“), sollte das nicht über Links (GET) passieren. GET ist für „Daten holen“ gedacht.

Merke
GET liest, POST ändert (Faustregel)

In der Praxis gilt: Alles, was einen Effekt hat, ist mindestens POST. Und bei POST brauchst du CSRF-Schutz.

3) Die Lösung: CSRF-Token (ein geheimes Extra-Feld)

Ein CSRF-Token ist ein zufälliger Wert, den du beim Anzeigen eines Formulars erzeugst und in der Session speicherst. Beim Absenden muss derselbe Token wiederkommen.

Eine fremde Webseite kennt dieses Token nicht – also kann sie keinen gültigen Request bauen. Genau das verhindert CSRF.

Prinzip: Token generieren

session_start();

// Token nur erstellen, wenn noch keiner da ist (oder pro Formular)
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

$token = $_SESSION['csrf_token'];

Dann fügst du ihn in dein Formular ein:

Token im Formular

<form method="post">
  <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($token, ENT_QUOTES, 'UTF-8') ?>">

  <!-- weitere Felder -->

  <button type="submit">Speichern</button>
</form>

4) Token prüfen (und warum timing-safe wichtig ist)

Beim POST prüfst du, ob der gesendete Token zum Session-Token passt. Dafür nutzt man in PHP am besten hash_equals() (das ist „timing-safe“, also schwerer auszutricksen).

Token prüfen

session_start();

$posted = $_POST['csrf_token'] ?? '';
$stored = $_SESSION['csrf_token'] ?? '';

if ($posted === '' || $stored === '' || !hash_equals($stored, $posted)) {
    // Request ist nicht vertrauenswürdig
    http_response_code(403);
    echo "Ungültiger CSRF-Token";
    exit;
}

// ab hier: Request ist ok (zumindest CSRF-technisch)
Achtung
Ohne CSRF-Token sind POST-Formulare oft angreifbar

Besonders bei Aktionen wie „E-Mail ändern“, „Passwort ändern“, „Adresse ändern“, „Löschen“ oder „Bestellung auslösen“.

5) SameSite-Cookies helfen – ersetzen Token aber nicht komplett

Moderne Browser unterstützen Cookie-Flags wie SameSite. Damit kann man viele CSRF-Szenarien erschweren.

Trotzdem gilt: CSRF-Tokens sind der „klassische“ und sehr zuverlässige Schutz, besonders wenn du Formulare und Sessions nutzt.

Tipp
Defense in Depth

Gute Praxis ist: Tokens und sinnvolle Cookie-Flags (SameSite, Secure, HttpOnly), statt nur auf einen Schutz zu setzen.

Kleine Aufgaben (zum Mitdenken)

Aufgabe 1: Warum reicht „POST“ alleine nicht?

Viele sagen: „Wir nutzen doch POST, also ist es sicher.“ Warum ist das bei CSRF nicht ausreichend?

Lösung einblenden
Lösung
Der Browser sendet Cookies auch bei POST automatisch mit

POST verhindert nicht, dass ein fremder Kontext einen Request auslöst. Wenn Cookies (Session) automatisch mitgesendet werden, kann der Request trotzdem „authentisch“ wirken. Ein Token stellt sicher, dass der Request wirklich von deiner Seite stammt.