Sessions und CSRF-Schutz in PHP – Formulare gegen Fremdzugriff absichern
Ein Login ohne CSRF-Schutz lässt sich von fremden Seiten missbrauchen. Ich zeige dir das Token-Muster, das jedes Formular absichert – erzeugen, verstecktes Feld, per hash_equals prüfen – plus die richtigen Session-Cookie-Einstellungen.
Sobald ein PHP-Formular etwas verändert (Login, Speichern, Löschen), braucht es einen CSRF-Schutz. Ohne ihn könnte eine fremde Website deinen eingeloggten Nutzer heimlich ein Formular absenden lassen. Das Gegenmittel ist ein geheimes Token pro Session.
Session sicher starten
<?php
declare(strict_types=1);
session_set_cookie_params([
'httponly' => true, // kein Zugriff per JavaScript (schützt vor XSS-Diebstahl)
'samesite' => 'Lax', // Cookie nicht bei fremden Cross-Site-Requests senden
'secure' => true, // nur über HTTPS
]);
session_start();Token erzeugen und ins Formular legen
function csrf_token(): string
{
if (empty($_SESSION['csrf'])) {
$_SESSION['csrf'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf'];
}
?>
<form method="post" action="/speichern.php">
<input type="hidden" name="csrf" value="<?= htmlspecialchars(csrf_token()) ?>">
<!-- weitere Felder -->
<button type="submit">Speichern</button>
</form>Beim Absenden prüfen
function check_csrf(): void
{
$sent = $_POST['csrf'] ?? '';
if (!is_string($sent) || !hash_equals($_SESSION['csrf'] ?? '', $sent)) {
http_response_code(419);
exit('Sitzung abgelaufen. Bitte lade die Seite neu.');
}
}Zwei Details sind wichtig: random_bytes liefert ein kryptografisch sicheres Token (nicht rand()), und hash_equals vergleicht zeitkonstant – ein normaler ===-Vergleich könnte über minimale Zeitunterschiede angreifbar sein.
Ruf check_csrf() ganz am Anfang jedes POST-Handlers auf, bevor irgendetwas gespeichert wird. Genau dieses Muster steckt auch im Admin-Backend, das ich für meine Kunden baue. Mehr auf bymw.de.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
Beträge und Zahlen in PHP formatieren – number_format, sprintf und Intl
1234.5 ist keine Anzeige, sondern ein Wert. Auf der Rechnung soll 1.234,50 € stehen, in der API 1234.50 und im Dateinamen 1234-50. Drei Aufgaben, drei Werkzeuge – und ein Fehler, den fast jeder einmal macht.
Benannte Argumente in PHP 8 – Schluss mit true, false, null, true
Ein Aufruf wie erstelle($a, true, false, null, true) sagt nichts darüber, was die Wahrheitswerte bedeuten. Mit benannten Argumenten steht es im Aufruf – und optionale Parameter lassen sich überspringen.
Reguläre Ausdrücke in PHP – benannte Gruppen statt $m[3]
Ein Treffer-Array aus Zahlen liest sich nach zwei Wochen wie eine Geheimschrift. Benannte Gruppen geben jedem Teil einen Namen – und preg_replace_callback ersetzt damit Dinge, die kein einfacher Ersetzungsstring kann.