jwtdecoder.de

Ratgeber · JWT 2026

alg=none - wie Libraries Token einfach akzeptierten

Was 2015 mehrere Libraries gleichzeitig hatten: Algorithm-Verwechslung. Wie man das heute zuverlässig verhindert (Algorithm-Whitelisting).

Foto von Jan-Tristan Rudat

Von Jan-Tristan Rudat

Redakteur jwtdecoder.de

Eine der berühmtesten JWT-Schwachstellen

2015 deckte Tim McLean (Auth0) eine kritische Schwachstelle in mehreren JWT-Libraries auf: sie akzeptierten Tokens mit Header {"alg":"none"} als gültig - ohne Signaturprüfung. Angreifer konnte Tokens mit beliebigen Claims bauen und Server akzeptierten sie.

Wie der Angriff funktioniert

Standard-JWT mit HS256: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhbGljZSJ9.SIGNATURE

Angreifer-modifiziertes JWT mit alg=none:

// Header: { "alg": "none", "typ": "JWT" }
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0

// Payload: { "sub": "admin" }
.eyJzdWIiOiJhZG1pbiJ9

// Signature: leer
.

// Vollständiges Token:
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiJ9.

Naive Verifier-Code:

function verifyToken(token, secret) {
  const [headerB64, payloadB64, sigB64] = token.split('.');
  const header = JSON.parse(atob(headerB64));

  // BUG: alg=none wird hier "respektiert"
  if (header.alg === 'none') {
    return JSON.parse(atob(payloadB64));  // accept!
  }

  // sonst HMAC prüfen...
}

Server gibt Admin-Rechte. Angreifer hat das System ohne Schlüssel kompromittiert.

Warum das Pattern in Libraries vorkam

RFC 7519 erlaubt unsigned JWTs (alg=none) für Use-Cases ohne Signaturanforderung. Library-Autoren wollten konform sein und unterstützten die Variante. Defaults waren oft "alle Algorithmen erlauben", nicht "explicit opt-in".

Die 2015er Welle traf: PyJWT, jose4j, ruby-jwt, node-jsonwebtoken - alle in verschiedenen Versionen. Alle haben das gepatched.

Der Fix: Algorithm-Whitelist

Der Verifier muss eine explizite Liste erlaubter Algorithmen führen und alles andere ablehnen. Beispiele:

// PyJWT (modern)
jwt.decode(token, key, algorithms=['HS256'])  // alles andere wird abgelehnt

// node-jsonwebtoken
jwt.verify(token, secret, { algorithms: ['HS256'] })

// Java/jose4j
new JwtConsumerBuilder()
  .setVerificationKey(key)
  .setJwsAlgorithmConstraints(
    AlgorithmConstraints.ConstraintType.PERMIT,
    AlgorithmIdentifiers.HMAC_SHA256
  )
  .build();

Wenn alg-Whitelist gesetzt ist UND "none" nicht drauf steht → Library lehnt Token mit alg=none ab, bevor Signatur überhaupt geprüft wird.

Verwandte Schwachstelle: Algorithm-Confusion

Eine subtilere Variante: Verifier erwartet RS256 (asymmetrisch). Angreifer ändert alg auf HS256 (symmetrisch) und signiert das Token mit dem Public Key (öffentlich bekannt) als HMAC-Secret.

Wenn die Library den Verification-Key blind als HMAC-Secret durchreicht, stimmt die Signatur - und Angreifer hat gültiges Token, weil er den Public Key kennt.

Fix: nicht nur alg whitelisten, sondern auch Key-Type prüfen. Bei vielen Libraries muss man explizit zwei Code-Pfade für HMAC vs Asymmetrisch trennen.

Wie verifiziert man heute, dass man sicher ist?

  1. Library-Version aktuell halten: alle modernen Versionen (PyJWT ≥ 2.0, node-jsonwebtoken ≥ 9.0, jose4j ≥ 0.9) haben sichere Defaults.
  2. algorithms-Parameter explizit setzen: nie auf Defaults vertrauen.
  3. Negative Tests in CI: einen Test, der ein alg=none-Token gegen den Verifier wirft und assertet, dass es abgelehnt wird.
  4. Pentest: extern, alle 6-12 Monate. Wäre die "Internal-Audit"-Sicht oft nicht aufgefallen.

Negative-Test-Code (Beispiel Node.js)

test('rejects alg=none', () => {
  const evilToken = createUnsecuredJWT({ sub: 'admin' });
  expect(() =>
    jwt.verify(evilToken, secret, { algorithms: ['HS256'] })
  ).toThrow();
});

test('rejects RS256 token with HMAC-substituted alg', () => {
  // Build a token: alg=HS256, signed with publicKey as HMAC-secret
  const tokenForged = createHMACSignedToken(publicKey, { sub: 'admin' });
  expect(() =>
    jwt.verify(tokenForged, publicKey, { algorithms: ['RS256'] })
  ).toThrow();
});

Real-World-Case

Siehe Case-Study alg=none Sicherheitslücke aufgedeckt - Pentest aus 2024 bei einem deutschen Mittelstands-Unternehmen, das eine veraltete jose4j-Version benutzte.

Im JWT Decoder erkennt das Tool alg=none-Tokens und zeigt einen entsprechenden Warning - der Decode funktioniert (weil das Format trivial ist), aber als "nicht verifizierbar" markiert.

Mehr zum Thema