Tokens, SameSite und Fetch richtig kombinieren
Cross Site Request Forgery gilt in vielen Teams als gelöstes Problem, sobald eine Anwendung auf eine Single Page Architektur mit Fetch statt klassischer Formulare umsteigt. Tatsächlich verschiebt sich das Risiko nur, sobald Session Cookies für authentifizierte API Aufrufe im Spiel sind, bleibt aber real und erfordert eine bewusste Kombination aus Double-Submit-Cookie, SameSite-Attribut und Custom Headern.
Inhaltsverzeichnis
Elf Abschnitte von der Grundlagenklärung über Double-Submit-Cookie bis zur Token Rotation für kritische API Endpunkte.
- 1. Warum CSRF in Single Page Apps unterschätzt wird
- 2. SameSite Cookies als erste Verteidigungslinie
- 3. Double-Submit-Cookie Pattern im Detail
- 4. Custom Header als impliziter CSRF Schutz
- 5. Token Handling in Fetch und Axios Interceptors
- 6. Token Rotation und Ablaufzeiten
- 7. Cross Origin APIs und Drittanbieter Integrationen
- 8. Typische Fehler bei der CSRF Implementierung
- 9. CSRF Schutzmaßnahmen im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum CSRF in Single Page Apps unterschätzt wird
CSRF Schutz wird in Single Page App Projekten häufig fälschlich als erledigt betrachtet, sobald keine klassischen HTML Formulare mehr existieren. Das Missverständnis entsteht, weil viele Teams Cross Site Request Forgery mit dem klassischen Formular Angriff gleichsetzen, bei dem eine fremde Seite ein verstecktes Formular automatisch absendet. Solange die Anwendung jedoch weiterhin Cookie basierte Sessions für authentifizierte Fetch Aufrufe verwendet, bleibt derselbe Grundmechanismus angreifbar: Der Browser sendet Cookies automatisch mit, unabhängig davon, ob der Request von der eigenen Seite oder einer fremden Domain ausgelöst wurde.
Der Unterschied zur klassischen Formular basierten Anwendung liegt im Detail: Ein Angreifer kann zwar keinen einfachen HTML Formular Submit mehr nutzen, aber ein einfacher fetch Aufruf mit credentials: 'include' von einer fremden, bösartigen Seite erreicht denselben Effekt, sofern kein zusätzlicher CSRF Schutz greift. Nutzt die Anwendung stattdessen ausschließlich Token basierte Authentifizierung ohne Cookies, etwa einen im JavaScript Speicher gehaltenen Bearer Token, entfällt das klassische CSRF Risiko tatsächlich, dafür entstehen andere Risiken wie XSS basierter Token Diebstahl. Für Cookie basierte Sessions bleibt CSRF Schutz also unverzichtbar.
Besonders trügerisch wird die Lage, wenn eine Anwendung mehrere Authentifizierungsmechanismen parallel betreibt, etwa Token basierte Authentifizierung für die eigentliche API und Cookie basierte Sessions für einen separaten Admin Bereich. In diesem Fall reicht ein einziger vergessener Endpunkt ohne CSRF Schutz aus, um die gesamte Absicherung des restlichen Systems zu untergraben.
2. SameSite Cookies als erste Verteidigungslinie
Das SameSite Attribut eines Cookies ist die einfachste und wirksamste erste Verteidigungslinie gegen Cross Site Request Forgery. Mit SameSite=Strict sendet der Browser das Cookie ausschließlich bei Requests, die von derselben Seite ausgehen, ein von einer fremden Domain initiierter Request enthält das Session Cookie dann gar nicht erst. SameSite=Lax, der Standardwert in modernen Browsern, erlaubt das Cookie bei einfachen Navigations Requests wie Links, blockiert es aber bei POST Requests von fremden Seiten, was für die meisten API Aufrufe bereits ausreichenden Schutz bietet.
Der entscheidende Vorbehalt: SameSite allein ist kein vollständiger CSRF Schutz, weil ältere Browser das Attribut ignorieren können und weil Subdomain Konfigurationen in komplexen Setups Lücken öffnen, etwa wenn eine kompromittierte Subdomain als same site gilt. SameSite=Strict sollte für Session Cookies der Standard sein, ergänzt durch ein zweites, unabhängiges Schutzmuster wie das Double-Submit-Cookie Pattern für Requests, die tatsächlich Zustandsänderungen auslösen.
Set-Cookie: session_id=abc123; SameSite=Strict; Secure; HttpOnly; Path=/
3. Double-Submit-Cookie Pattern im Detail
Das Double-Submit-Cookie Pattern basiert auf einer einfachen Idee: Der Server setzt einen zufälligen CSRF Token sowohl als lesbares Cookie als auch erwartet ihn zusätzlich als Wert in einem Custom Header oder Request Body. Ein Angreifer kann zwar das Cookie automatisch mitsenden lassen, hat aber keinen Zugriff auf dessen Wert, um ihn im Header zu duplizieren, weil die Same Origin Policy das Auslesen fremder Cookies per JavaScript verhindert.
Wichtig für Single Page Apps: Das CSRF Token Cookie darf nicht HttpOnly sein, da JavaScript es explizit auslesen und in den Header kopieren muss. Das eigentliche Session Cookie hingegen sollte immer HttpOnly bleiben, um es vor XSS basiertem Diebstahl zu schützen. Diese Trennung zwischen einem für JavaScript lesbaren CSRF Token Cookie und einem versteckten, HttpOnly Session Cookie ist der Kern eines robusten CSRF Schutzes in modernen Single Page Apps.
// Read the CSRF token from a non-HttpOnly cookie and attach it as a header
function getCsrfToken() {
const match = document.cookie.match(/(?:^|;\s*)csrf_token=([^;]+)/);
return match ? decodeURIComponent(match[1]) : null;
}
async function apiPost(url, body) {
const response = await fetch(url, {
method: 'POST',
credentials: 'include', // send the HttpOnly session cookie
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': getCsrfToken(), // server compares this to the session's stored token
},
body: JSON.stringify(body),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
return response.json();
}
4. Custom Header als impliziter CSRF Schutz
Neben dem eigentlichen Token Vergleich existiert eine zweite, unabhängige Schutzebene, die sich fast beiläufig aus der bestehenden API Architektur einer Single Page App ergibt und in der Praxis häufig übersehen wird.
Ein oft übersehener, aber wirksamer CSRF Schutz ergibt sich allein aus der Verwendung eines Custom Headers wie X-Requested-With oder X-CSRF-Token, unabhängig vom eigentlichen Token Wert. Klassische HTML Formulare können keine Custom Header setzen, ein einfacher Cross Site Formular Angriff scheitert also bereits daran, dass der erwartete Header schlicht fehlt. Fetch Aufrufe von einer fremden Origin lösen bei Custom Headern zudem eine CORS Preflight Anfrage aus, die der Server ablehnen kann, wenn die anfragende Origin nicht in der erlaubten Liste steht.
Dieser implizite Schutz ist wertvoll, aber kein Ersatz für einen expliziten Token Vergleich, weil ein falsch konfigurierter CORS Header, etwa ein zu freizügiges Access-Control-Allow-Origin: * in Kombination mit erlaubten Credentials, die Schutzwirkung wieder aufheben kann. Server sollten CORS Konfiguration und CSRF Token Prüfung als zwei unabhängige Kontrollen behandeln, nicht als austauschbare Alternativen.
5. Token Handling in Fetch und Axios Interceptors
Sauberes Token Handling ist letztlich eine Frage der Codeorganisation, nicht der Kryptographie, und genau deshalb lohnt sich ein Blick auf bewährte Muster aus großen Produktionscodebasen.
In größeren Single Page Apps mit vielen API Aufrufen lohnt sich eine zentrale Stelle für das Token Handling, statt den CSRF Token in jedem einzelnen fetch Aufruf manuell zu setzen. Ein Axios Interceptor oder ein Wrapper um die native Fetch API liest das Token Cookie einmalig aus und fügt den Header automatisch bei jedem ausgehenden Request hinzu, was Kopierfehler und vergessene Header in einzelnen Codepfaden verhindert.
Bei serverseitig gerenderten Frameworks wie Next.js oder Nuxt, die sowohl klassische Formulare als auch Fetch basierte API Routen unterstützen, muss der Interceptor zusätzlich zwischen initial serverseitig gerendertem Token und clientseitig aktualisiertem Token unterscheiden. Ein nach Login neu ausgestelltes Token muss den im Speicher gehaltenen Wert im Interceptor ersetzen, sonst schlagen nachfolgende Requests mit einem veralteten Token fehl.
// Centralized Axios interceptor for CSRF token handling
import axios from 'axios';
const api = axios.create({ baseURL: '/api', withCredentials: true });
api.interceptors.request.use((config) => {
const token = getCsrfToken();
if (token && ['post', 'put', 'patch', 'delete'].includes(config.method)) {
config.headers['X-CSRF-Token'] = token;
}
return config;
});
export default api;
Für React und Vue Anwendungen mit mehreren unabhängigen API Clients lohnt sich zusätzlich eine gemeinsame Utility Funktion, die von allen Clients importiert wird, statt den Token Lese Code in jedem Client separat zu duplizieren. Das reduziert die Wahrscheinlichkeit, dass ein neuer Client versehentlich ohne CSRF Header aufgesetzt wird.
6. Token Rotation und Ablaufzeiten
Ein statisches CSRF Token, das über die gesamte Session Lebensdauer unverändert bleibt, ist grundsätzlich sicher, verringert aber die Widerstandsfähigkeit gegen bestimmte fortgeschrittene Angriffsszenarien wie Session Fixation. Best Practice ist, das CSRF Token bei jedem Login neu zu generieren und optional nach einer definierten Zeitspanne oder nach sensiblen Aktionen wie Passwortänderungen zu rotieren.
Wichtig bei der Rotation: Der Server muss das alte Token für eine kurze Übergangszeit noch akzeptieren, wenn mehrere Browser Tabs oder Requests parallel im Flug sind, sonst schlagen legitime, gleichzeitig gesendete Requests fehl. Ein üblicher Ansatz ist, das neue Token in der Response eines beliebigen API Aufrufs mitzuschicken und clientseitig automatisch zu übernehmen, ohne dass der Nutzer die Seite neu laden muss.
7. Cross Origin APIs und Drittanbieter Integrationen
Getrennte Domains für Frontend und Backend sind in modernen Architekturen der Normalfall, weshalb sich jedes Team frühzeitig mit den Besonderheiten der Cross Origin Kommunikation auseinandersetzen sollte, bevor der erste zustandsverändernde Endpunkt produktiv geschaltet wird.
Single Page Apps, die eine separate API Domain nutzen, etwa app.mironsoft.de für das Frontend und api.mironsoft.de für das Backend, stehen vor einer zusätzlichen Herausforderung: SameSite=Strict Cookies funktionieren zwischen unterschiedlichen Subdomains je nach Browser Interpretation nicht immer zuverlässig als same site. In diesem Fall ist SameSite=Lax in Kombination mit einem strikten Double-Submit-Cookie Pattern oft die praktikablere Wahl, weil sie echte Cross Site Angriffe weiterhin blockiert, ohne legitime Subdomain Kommunikation zu brechen.
Für Drittanbieter Integrationen, etwa ein eingebettetes Zahlungswidget, das selbst API Aufrufe an die Hauptanwendung auslöst, muss der CSRF Schutz explizit für diesen Fall getestet werden. Ein iframe eingebettetes Widget hat je nach Kontext keinen Zugriff auf das CSRF Token Cookie der Hauptanwendung, was zu unerwarteten 403 Fehlern führt, wenn dieser Fall nicht in der Token Distribution berücksichtigt wurde.
In Magento und Hyvä basierten Shops mit eigenen, per Fetch angebundenen Alpine.js Komponenten sollte der CSRF Token immer zentral über eine einzige gemeinsame Konfigurationsstelle bereitgestellt werden, statt ihn in jeder Komponente einzeln aus dem Cookie zu lesen. Das erleichtert eine spätere Migration auf ein anderes Token Format erheblich.
8. Typische Fehler bei der CSRF Implementierung
Der häufigste Fehler ist die Annahme, dass credentials: 'omit' oder das vollständige Weglassen von Cookies automatisch CSRF sicher macht, während die Anwendung an anderer Stelle doch wieder Cookie basierte Sessions nutzt, etwa für einen separaten Admin Bereich. Ein zweiter Fehler ist das Speichern des CSRF Tokens im localStorage statt in einem eigenen, nicht HttpOnly Cookie, was zwar funktional ähnlich wirkt, aber bei einer XSS Schwachstelle zusätzliche Angriffsfläche für Token Diebstahl über localStorage Zugriff öffnet.
Ein dritter Fehler betrifft GET Requests: Manche Teams schützen nur POST, PUT und DELETE Requests, vergessen aber, dass ein GET Request mit Seiteneffekten, etwa ein Logout Endpunkt über GET, ebenfalls fälschungssicher gemacht werden muss. Die REST Konvention, GET Requests niemals Zustandsänderungen auslösen zu lassen, ist damit nicht nur ein API Design Prinzip, sondern eine direkte CSRF Schutz Maßnahme.
9. CSRF Schutzmaßnahmen im Vergleich
Nach der Betrachtung der einzelnen Bausteine lohnt sich ein zusammenfassender Blick, der Sicherheitsniveau, Aufwand und Grenzen jeder Maßnahme nebeneinanderstellt, damit die richtige Kombination für das jeweilige Projekt bewusst gewählt werden kann.
Die folgende Tabelle stellt die wichtigsten Schutzmaßnahmen gegenüber, die in Single Page Apps kombiniert werden sollten.
| Maßnahme | Schutzwirkung | Implementierungsaufwand | Grenzen |
|---|---|---|---|
| SameSite Cookie | Blockiert die meisten Cross Site Requests | Sehr gering, ein Attribut | Ältere Browser, komplexe Subdomains |
| Double-Submit-Cookie | Erkennt fehlenden Header explizit | Client und Server Anpassung nötig | Token Cookie darf nicht HttpOnly sein |
| Custom Header | Blockiert klassische Formular Angriffe | Gering | Abhängig von korrekter CORS Konfiguration |
| Token Rotation | Reduziert Angriffsfenster bei Token Leak | Mittel, Übergangslogik nötig | Race Conditions bei mehreren Tabs |
In der Praxis ist keine dieser Maßnahmen für sich allein ausreichend robust. Die Kombination aus SameSite=Strict oder Lax, einem Double-Submit-Cookie Pattern über einen Custom Header und regelmäßiger Token Rotation ergibt einen mehrschichtigen CSRF Schutz, der auch bei einem teilweisen Versagen einer einzelnen Schicht wirksam bleibt.
Ein regelmäßiger Penetrationstest, der gezielt versucht, zustandsverändernde Endpunkte ohne gültigen CSRF Token anzusprechen, ist die zuverlässigste Methode, um die tatsächliche Wirksamkeit der implementierten Schutzschichten zu verifizieren, statt sich allein auf die theoretische Korrektheit der Konfiguration zu verlassen.
Mironsoft
Single Page App Sicherheit, CSRF Audits und API Härtung
CSRF Schutz für eure Single Page App richtig aufsetzen?
Wir prüfen eure bestehende Fetch und Axios Integration, entwerfen ein passendes Double-Submit-Cookie Pattern und richten Token Rotation für kritische Endpunkte ein, ohne bestehende API Verträge zu brechen.
CSRF Audit
Analyse aller zustandsverändernden Endpunkte und Cookie Konfiguration
Token Integration
Zentrales Token Handling in Fetch Wrappern und Axios Interceptors
Cross Origin Setup
SameSite und CORS Konfiguration für getrennte API Domains
10. Zusammenfassung
Zum Abschluss lohnt sich der Blick zurück auf die zentrale Erkenntnis dieses Artikels: Fetch statt Formular ändert den Angriffsvektor, nicht aber die Notwendigkeit eines durchdachten Schutzkonzepts gegen Cross Site Request Forgery.
CSRF Schutz in Single Page Apps ist kein gelöstes Problem nur weil klassische HTML Formulare durch Fetch Aufrufe ersetzt wurden. Solange Cookie basierte Sessions im Spiel sind, bleibt der Grundmechanismus des automatischen Cookie Versands angreifbar, und erfordert eine bewusste, mehrschichtige Verteidigung. SameSite=Strict oder Lax als erste Schicht, ein Double-Submit-Cookie Pattern mit Custom Header als zweite, unabhängige Schicht, und regelmäßige Token Rotation als dritte Schicht ergeben zusammen einen robusten Schutz.
Zentrales Token Handling über Fetch Wrapper oder Axios Interceptors reduziert das Risiko vergessener Header in einzelnen Codepfaden erheblich. Wer CSRF Schutz von Anfang an in die zentrale API Schicht der Anwendung integriert, statt ihn nachträglich in jeden einzelnen Aufruf einzubauen, spart sich aufwendige Nacharbeit und schließt die Lücke systematisch statt punktuell.
CSRF-Schutz in Single Page Apps — Das Wichtigste auf einen Blick
Vier Bausteine, die zusammen einen mehrschichtigen CSRF Schutz für Fetch basierte Anwendungen ergeben.
SameSite
SameSite=Strict oder Lax blockiert die meisten Cross Site Requests, ist aber kein alleiniger Schutz.
Double-Submit-Cookie
Ein für JavaScript lesbares Token Cookie plus Custom Header, verglichen mit dem Session Cookie serverseitig.
Zentrales Handling
Axios Interceptor oder Fetch Wrapper setzt den Header automatisch bei jedem Request.
Token Rotation
Neuer Token bei Login und sensiblen Aktionen, mit kurzer Übergangszeit für parallele Requests.
Gemeinsam bilden diese vier Bausteine eine mehrschichtige Verteidigung, die auch bei Teilausfall einer Schicht wirksam bleibt.
11. FAQ: CSRF-Schutz in Single Page Apps
Die folgenden zehn Fragen fassen die häufigsten praktischen Unsicherheiten zu CSRF Schutz in Single Page Apps zusammen.