Zum Inhalt springen

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen
Web-Sicherheit Glossar

CSRF (Cross-Site Request Forgery)

Cross-Site Request Forgery (CSRF) ist ein Angriff bei dem ein Angreifer den Browser eines angemeldeten Nutzers dazu bringt, unbeabsichtigte HTTP-Anfragen an eine Webanwendung zu senden - im Namen des Nutzers, ohne sein Wissen. Zählt zu den OWASP Top 10 und ist besonders gefährlich bei state-changing Aktionen.

CSRF-Angriffe nutzen das Vertrauen aus, das Browser-Sessions aufgebaut haben: Cookies werden automatisch mitgesendet - auch wenn der Request von einer fremden Website kommt. Ein einziger Klick auf einen präparierten Link kann Kontoeinstellungen ändern, Transaktionen auslösen oder Accounts übernehmen.

Wie CSRF funktioniert

Das Angriffsszenario einer Geldüberweisung verläuft in sechs Schritten:

  1. Das Opfer ist bei bank.de eingeloggt (Session-Cookie vorhanden).
  2. Der Angreifer erstellt eine präparierte Webseite unter evil.com/malicious.html.
  3. Das Opfer klickt auf einen Link zu evil.com, z.B. über eine Phishing-Mail.
  4. evil.com lädt im Browser des Opfers entweder ein verstecktes Bild-Tag (<img src="https://bank.de/transfer?amount=1000&to=attacker" />) oder ein automatisch abgesendetes verstecktes Formular.
  5. Der Browser sendet den Request zu bank.de - mit dem Session-Cookie des Opfers, automatisch und ohne Wissen des Opfers.
  6. bank.de hält den Request für einen legitimen Nutzeraufruf und führt die Überweisung aus.

Bedingungen für CSRF

  • Das Opfer muss eingeloggt sein (Session-Cookie gültig)
  • Die Anwendung prüft nicht, ob der Request von der eigenen Seite stammt
  • Der Angreifer kennt die Ziel-URL (oft leicht zu erraten)
  • Keine CSRF-Schutzmaßnahmen sind implementiert

CSRF vs. XSS - Wichtiger Unterschied

EigenschaftXSSCSRF
AngriffsrichtungAngreifer injiziert JavaScript in die Ziel-WebsiteAngreifer täuscht Browser, Request zu senden
KontrolleAngreifer kontrolliert Code im Kontext der Ziel-SiteAngreifer sieht die Response nicht (Same-Origin Policy)
Gefährliche AktionenCookies stehlen, Formulardaten abgreifenNur state-changing Aktionen (POST/PUT/DELETE)
CSRF-SchutzUmgeht CSRF-Schutz (Code im selben Origin)GET-Requests die Daten ändern sind besonders gefährdet

Merkhilfe: XSS lässt Angreifer Browser-Daten lesen und manipulieren. CSRF täuscht den Browser, Aktionen im Namen des Nutzers auszuführen.

CSRF-Schutzmaßnahmen

1. CSRF-Tokens (Synchronizer Token Pattern) - Hauptmaßnahme

Der Server generiert einen zufälligen Token, speichert ihn in der Session und bettet ihn in jedes Formular ein. Bei jedem State-Changing-Request prüft der Server, ob der mitgesendete Token mit dem Session-Token übereinstimmt.

<form action="/transfer" method="POST">
  <input type="hidden" name="_csrf" value="a9d3e7b2c4f1..." />
  <input name="amount" />
  <button>Überweisen</button>
</form>
// Express.js mit csurf:
import csrf from 'csurf';
const csrfProtection = csrf({ cookie: false });  // Session-basiert!

app.get('/transfer', csrfProtection, (req, res) => {
  res.render('transfer', { csrfToken: req.csrfToken() });
});

app.post('/transfer', csrfProtection, (req, res) => {
  // csurf prüft Token automatisch!
  // Wenn Token fehlt/falsch → 403 Forbidden
});

Das SameSite-Attribut steuert, wann Cookies bei Cross-Site-Requests mitgesendet werden:

WertVerhaltenEinsatz
StrictCookie wird nie bei Cross-Site-Requests gesendet - absoluter CSRF-SchutzProblematisch: Nutzer der über externen Link kommt, ist nicht eingeloggt
LaxCookie nur bei Top-Level-Navigation mit GETEmpfehlung für die meisten Apps; schützt vor CSRF-Formularen (POST), erlaubt normale externe Links
None; SecureCookie bei allen Cross-Site-Requests - nur mit HTTPSNur für CORS-APIs die Cookies brauchen (z.B. Widgets)
Set-Cookie: session=abc; SameSite=Lax; Secure; HttpOnly; Path=/

Hinweis: Seit Chrome 80 ist SameSite=Lax der Default, wenn kein SameSite-Attribut gesetzt ist.

Als Alternative wenn serverseitige Sessions nicht verfügbar sind:

  1. Server setzt CSRF-Token als Cookie (nicht httpOnly!)
  2. JavaScript liest den Cookie und sendet den Token im Request-Header
  3. Server prüft: Cookie-Token == Header-Token?

Vorteil: Funktioniert ohne serverseitige Session. Nachteil: Anfällig für Subdomain-Angriffe (XSS auf subdomain.firma.de kann den Cookie lesen und manipulieren).

4. Custom Request Header (für AJAX/APIs)

APIs die ausschließlich JSON akzeptieren, können folgende Header-Checks nutzen:

  • request.headers['X-Requested-With'] == 'XMLHttpRequest'
  • request.headers['Content-Type'] == 'application/json'

Normale Browser-Formulare können keine Custom-Headers senden - dieser Check funktioniert daher als impliziter CSRF-Schutz. Achtung: Nur für APIs verwenden, nicht für HTML-Formulare.

Gefährdete HTTP-Methoden

GET-Requests sollten niemals state-changing sein (REST-Prinzip). Sie sind besonders gefährdet, weil Browser, Crawler und Proxies GETs cachen und automatisch ausführen. Ein Beispiel für eine kritische Schwachstelle: <img src="https://example.com/delete-account">.

POST-, PUT- und DELETE-Requests sind das Hauptziel von CSRF und müssen mit Token oder SameSite geschützt werden.

Ausnahmen (kein CSRF-Schutz nötig):

  • Rein lesende GET-Requests ohne State Changes
  • Endpoints die nur via API genutzt werden (kein Browser-Cookie)
  • OAuth2-Token-Endpoints (kein Cookie) - aber: state-Parameter als CSRF-Schutz implementieren

CSRF in modernen SPAs

Single Page Applications (React, Vue, Angular) senden API-Requests per fetch oder axios, nicht über HTML-Formulare. Da Custom Headers gesetzt werden können, besteht ein natürlicher CSRF-Schutz für API-Calls. Cookies müssen jedoch weiterhin geschützt werden.

Modernes Setup für SPAs

Backend (Express) mit JWT im Authorization-Header:

// JWT im Authorization-Header: KEIN CSRF-Problem!
// Cross-Site-Formulare können keinen Authorization-Header senden.

// Session/Cookie-Auth: SameSite=Lax reicht meist:
res.cookie('session', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'lax'
});

Frontend (React) mit JWT:

// Authorization Header (JWT): kein Cookie → kein CSRF
fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ amount: 100 }),
});

// Cookie-Auth mit CSRF-Token:
fetch('/api/transfer', {
  method: 'POST',
  credentials: 'include',          // Cookie mitsenden
  headers: {
    'X-CSRF-Token': csrfToken,     // Token aus Meta-Tag oder API
    'Content-Type': 'application/json',
  },
});

CSRF in Penetrationstests erkennen

Manuelle CSRF-Tests

  1. State-changing Endpoints identifizieren: Alle POST/PUT/DELETE-Requests mit Burp Suite protokollieren, CSRF-Token entfernen und prüfen ob der Request trotzdem erfolgreich ist.

  2. CSRF-Token-Qualität prüfen:

    • Ist der Token zufällig oder vorhersehbar?
    • Gilt der Token pro Session oder pro Request?
    • Ist der Token in der URL enthalten? (URL wird geloggt → Token-Leakage)
    • Ist der Token zu kurz? (weniger als 128 Bit Entropie)
  3. SameSite-Cookie prüfen: curl -v https://example.com/login und Set-Cookie Header auf SameSite prüfen.

  4. CORS-Headers prüfen: Access-Control-Allow-Origin: * kombiniert mit Access-Control-Allow-Credentials: true ist eine CORS-Misconfiguration.

  5. Referer-Header-Check: Requests ohne Referer-Header senden und prüfen ob akzeptiert. Dies ist eine schwache Maßnahme, da der Referer gefälscht werden kann.

Automatisierte Tools

  • Burp Suite: CSRF PoC Generator
  • OWASP ZAP: CSRF-Scanner
  • csrf-poc-generator (npm): automatische PoC-Erstellung

Beispiel: CSRF-PoC für Reporting

<!-- CSRF Proof-of-Concept (für Pentest-Reports) -->
<!DOCTYPE html>
<html>
<head><title>CSRF PoC</title></head>
<body>
  <h1>CSRF Test - Automatischer POST nach bank.de</h1>
  <form id="csrf-form"
        action="https://bank.de/api/transfer"
        method="POST">
    <input type="hidden" name="amount" value="1000" />
    <input type="hidden" name="recipient" value="IBAN_ANGREIFER" />
    <input type="hidden" name="note" value="CSRF-Test" />
  </form>
  <script>
    // Automatisches Absenden ohne Nutzerinteraktion
    document.getElementById('csrf-form').submit();
  </script>
</body>
</html>

CVSS-Bewertung (Beispiel: CSRF auf Kontoüberweisung)

MetrikWert
Attack VectorNetwork
Attack ComplexityLow
Privileges RequiredNone
User InteractionRequired
ScopeUnchanged
ConfidentialityNone
IntegrityHigh
AvailabilityNone
CVSS Base Score6.5 (Medium)

Die tatsächliche Einstufung ist hoch, wenn state-changing Aktionen betroffen sind wie Passwortänderungen, Admin-Rechtevergabe oder Datenlöschung.

Cookielose Analyse via Matomo (selbst gehostet, kein Tracking-Cookie). Datenschutzerklärung