Wie der Angriff funktioniert

Ein JWT besteht aus drei mit Punkten getrennten, Base64url-kodierten Teilen: Header (Metadaten inkl. Algorithmus "alg"), Payload (Claims wie sub, role, exp) und Signatur. Header und Payload sind nur kodiert, nicht verschlüsselt, also für jeden lesbar und veränderbar.

Die Sicherheit hängt allein an der kryptografischen Signatur, die der Server mit einem geheimen Schlüssel erzeugt und beim Empfang prüft. Angriffe entstehen, wenn diese Prüfung versagt:

  • alg=none / unsignierter Token - manche Implementierungen behandeln "none" als bereits verifizierte Signatur und vertrauen dem veränderten Token; Filter dagegen lassen sich teils durch Tricks wie gemischte Groß-/Kleinschreibung ("mixed capitalization") und unerwartete Kodierungen umgehen.
  • Fehlende Signaturprüfung - Entwickler verwechseln etwa in der Node.js-Bibliothek jsonwebtoken die Methode decode() (nur dekodieren) mit verify() (prüfen), sodass die Signatur gar nicht geprüft wird.
  • Algorithmus-Confusion (Key Confusion) - viele Bibliotheken bieten eine generische verify()-Methode, die anhand des "alg"-Headers entscheidet, wie geprüft wird. Erwartet der Code RS256 (asymmetrisch) und übergibt fest den öffentlichen Schlüssel, ein Angreifer setzt aber alg auf HS256 (symmetrisch), so verwendet die Bibliothek den öffentlichen Schlüssel als HMAC-Secret. Da dieser Schlüssel öffentlich bekannt ist, kann der Angreifer beliebige Tokens selbst gültig signieren.
  • Schwaches HMAC-Secret - bei HMAC-Algorithmen hängt alles am Secret; mit einem gültigen Token kann ein Angreifer offline per Brute Force (z. B. Hashcat, John the Ripper) das Secret knacken und dann beliebige Tokens neu signieren.
  • Fehlende Ablauf-/Audience-Prüfung und Replay - ohne Prüfung von exp/aud bleiben Tokens unbegrenzt gültig oder lassen sich auf anderen Diensten wiederverwenden.
1. AusgangslageServer akzeptiert JWTs
2. AngriffToken manipulieren: alg=none, Key Confusion, schwaches Secret
3. ErgebnisAls fremder Nutzer oder Admin akzeptiert

Fehlende oder falsche Signaturprüfung lässt gefälschte Tokens durch.

Beispiel

Algorithmus-Confusion (RS256 -> HS256), nach PortSwigger. Ausgangspunkt: Server gibt einen mit RS256 signierten Token aus und prüft ihn mit seinem öffentlichen Schlüssel.

  1. Schritt 1 - Angreifer holt den öffentlichen Schlüssel des Servers über einen Standard-Endpunkt: GET /.well-known/jwks.json liefert das JWK-Objekt (PortSwigger nennt /jwks.json oder /.well-known/jwks.json).
  2. Schritt 2 - Der Schlüssel wird ins passende Format gebracht (z. B. X.509 PEM), exakt identisch zur Server-Kopie inkl. nicht-druckbarer Zeichen wie Zeilenumbrüche.
  3. Schritt 3 - Angreifer baut einen Token mit verändertem Payload und setzt im Header "alg":"HS256": Header {"alg":"HS256"}, Payload {"sub":"administrator","role":"admin"}.
  4. Schritt 4 - Er signiert diesen Token per HMAC-SHA256 und benutzt den öffentlichen PEM-Schlüssel als HMAC-Secret.
  5. Schritt 5 - Er sendet den Token: GET /admin HTTP/1.1 ... Cookie: session=eyJhbGciOiJIUzI1NiJ9... Der Server ruft seine generische verify(token, secretOrPublicKey) auf, sieht alg=HS256 und prüft die HMAC-Signatur mit genau diesem öffentlichen Schlüssel - die Prüfung gelingt, der gefälschte Admin-Token wird akzeptiert.

Auswirkung

Erfolgreiche JWT-Angriffe sind meist hochkritisch: Ein Angreifer kann gefälschte, aber als gültig akzeptierte Tokens mit beliebigen Claims erzeugen und so die Authentifizierung und Zugriffskontrolle umgehen.

Typische Folge ist die Identitätsübernahme bereits authentifizierter Nutzer, insbesondere die Eskalation zu Administratorrechten (z. B. role von "user" auf "admin").

Da JWTs zentral für Authentifizierung, Session-Handling und Autorisierung verwendet werden, kann dies die gesamte Anwendung und ihre Nutzer kompromittieren.

So schützt man sich

  • Aktuelle, gepflegte JWT-Bibliothek verwenden und sicherstellen, dass die Entwickler ihre Funktionsweise und Sicherheitsimplikationen vollständig verstehen (PortSwigger).
  • Bei jedem empfangenen Token eine robuste Signaturprüfung durchführen und Edge-Cases wie unerwartete Algorithmen berücksichtigen - niemals nur decode() statt verify() aufrufen (PortSwigger).
  • Den erwarteten Algorithmus bei der Validierung explizit erzwingen, damit Tokens mit unerwartetem Algorithmus - etwa alg=none oder HS256 statt RS256 - abgelehnt werden (OWASP, PortSwigger).
  • HMAC-Secret stark und einzigartig wählen: mindestens 64 Zeichen aus einer sicheren Zufallsquelle; alternativ RSA statt HMAC nutzen (OWASP).
  • Für jeden ausgegebenen Token ein Ablaufdatum (exp) setzen (PortSwigger).
  • Den aud-Claim (Audience) setzen und prüfen, damit ein Token nicht auf anderen Diensten/Websites wiederverwendet werden kann (PortSwigger).
  • Tokens möglichst nicht in URL-Parametern übertragen und dem ausstellenden Server eine Token-Sperrung/Revocation ermöglichen, z. B. beim Logout (PortSwigger).
  • Bei Header-Parametern wie jku eine strikte Host-Whitelist erzwingen und kid gegen Path Traversal / SQL-Injection absichern (PortSwigger).

Quellen

Weiterlesen