CSRF-Schutz: Cross-Site Request Forgery verhindern | Enjyn Gruppe
Hallo Welt
Hallo Welt
Original Lingva Deutsch
Übersetzung wird vorbereitet...
Dieser Vorgang kann bis zu 60 Sekunden dauern.
Diese Seite wird erstmalig übersetzt und dann für alle Besucher gespeichert.
0%
DE Zurück zu Deutsch
Übersetzung durch Lingva Translate

235 Dokumentationen verfügbar

Wissensdatenbank

CSRF Schutz Implementieren

Zuletzt aktualisiert: 20.01.2026 um 10:03 Uhr

CSRF-Schutz: Cross-Site Request Forgery verhindern

CSRF lässt Angreifer Aktionen im Namen Ihrer Nutzer ausführen. Passwort ändern, Geld überweisen, Account löschen – ohne dass der Nutzer es merkt.

Was ist CSRF?

Ein Angreifer bringt einen eingeloggten Nutzer dazu, unbeabsichtigt eine Aktion auszuführen:

<!-- Auf bösartiger Website -->
<img src="https://bank.com/transfer?to=attacker&amount=10000">

<!-- Oder mit verstecktem Formular -->
<form action="https://bank.com/transfer" method="POST" id="evil">
  <input type="hidden" name="to" value="attacker">
  <input type="hidden" name="amount" value="10000">
</form>
<script>document.getElementById('evil').submit();</script>

Der Browser sendet automatisch die Session-Cookies mit – die Bank sieht eine authentifizierte Anfrage!

Lösung 1: CSRF-Token

Fügen Sie ein geheimes Token hinzu, das Angreifer nicht kennen können.

PHP Implementation

<?php
// Token generieren und in Session speichern
function generateCsrfToken(): string {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

// Token validieren
function validateCsrfToken(string $token): bool {
    return isset($_SESSION['csrf_token'])
        && hash_equals($_SESSION['csrf_token'], $token);
}
<!-- Im Formular -->
<form method="POST" action="/transfer">
    <input type="hidden" name="csrf_token" value="<?= generateCsrfToken() ?>">
    <input type="text" name="amount">
    <button type="submit">Überweisen</button>
</form>
<?php
// Bei der Verarbeitung
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!validateCsrfToken($_POST['csrf_token'] ?? '')) {
        http_response_code(403);
        die('CSRF-Token ungültig');
    }

    // Request verarbeiten...
}

Node.js mit Express

const csrf = require('csurf');
const cookieParser = require('cookie-parser');

app.use(cookieParser());
app.use(csrf({ cookie: true }));

// Token an Template übergeben
app.get('/form', (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});

// In EJS Template
<form method="POST">
  <input type="hidden" name="_csrf" value="<%= csrfToken %>">
  <button type="submit">Senden</button>
</form>

AJAX-Requests

// Token aus Meta-Tag lesen
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;

// Mit fetch senden
fetch('/api/action', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken
  },
  body: JSON.stringify(data)
});

// Oder mit axios
axios.defaults.headers.common['X-CSRF-Token'] = csrfToken;

Lösung 2: SameSite Cookies

Moderne Browser unterstützen das SameSite-Attribut:

// Cookies nicht bei Cross-Site Requests senden
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly

// Oder etwas lockerer (Links erlaubt, Formulare nicht)
Set-Cookie: session=abc123; SameSite=Lax; Secure; HttpOnly
SameSite Verhalten
Strict Nie bei Cross-Site Requests
Lax Nur bei Top-Level Navigation (Links)
None Immer (erfordert Secure)
<?php
// PHP: Session-Cookie mit SameSite
session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Strict'
]);
session_start();

Lösung 3: Double Submit Cookie

Alternative ohne Server-Session:

// 1. Token in Cookie UND in Request senden
// 2. Server vergleicht beide

// Cookie setzen (JavaScript-lesbar)
document.cookie = "csrf_token=random123; path=/; secure";

// Im Formular
<input type="hidden" name="csrf_token" value="random123">

// Server prüft: Cookie == Form-Wert?

Lösung 4: Origin/Referer Header prüfen

<?php
function checkOrigin(): bool {
    $origin = $_SERVER['HTTP_ORIGIN'] ?? '';
    $referer = $_SERVER['HTTP_REFERER'] ?? '';

    $allowedOrigins = ['https://example.com'];

    // Origin-Header bevorzugen
    if ($origin && in_array($origin, $allowedOrigins)) {
        return true;
    }

    // Fallback auf Referer
    if ($referer) {
        $refererHost = parse_url($referer, PHP_URL_HOST);
        return $refererHost === 'example.com';
    }

    return false;
}

Framework-spezifischer CSRF-Schutz

Laravel

{{-- Blade Template --}}
<form method="POST">
    @csrf
    ...
</form>

// Für AJAX
<meta name="csrf-token" content="{{ csrf_token() }}">

// In JavaScript
$.ajaxSetup({
    headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }
});

Django

{% csrf_token %}

// AJAX
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;

Spring Boot

<input type="hidden"
       name="${_csrf.parameterName}"
       value="${_csrf.token}"/>

Best Practices

💡 Empfehlungen:
  • CSRF-Token für alle state-ändernden Requests
  • SameSite=Strict oder Lax für Session-Cookies
  • Keine GET-Requests für Änderungen
  • Token pro Session oder pro Request
  • Sichere Zufallsgeneratoren verwenden

CSRF-Checkliste

  • ☐ CSRF-Token in allen Formularen
  • ☐ Token bei AJAX-Requests senden
  • ☐ SameSite-Attribut für Cookies
  • ☐ Token serverseitig validieren
  • ☐ Keine state-Änderungen via GET

Weitere Informationen

Enjix Beta

Enjyn AI Agent

Hallo 👋 Ich bin Enjix — wie kann ich dir helfen?
120