Wenn ich im JWT Header sehe:
{ "alg": "none" }
behandle ich das zunächst als unsecured JWT: Es gibt keine kryptografische Signatur, die Integrität oder Herkunft bestätigt. Dass der Standard diese Darstellung kennt, bedeutet nicht, dass eine normale API sie akzeptieren sollte.
Der JWT Security Analyzer markiert alg: none als Security-Finding, wenn ein signiertes Token-Profil erwartet wird.
Wie ein none-JWT aussieht
Ein compact unsecured JWT hat weiterhin drei Segmente, aber das Signatursegment ist leer:
eyJhbGciOiJub25lIn0.eyJzdWIiOiI0MiJ9.
Der letzte Punkt ist wichtig. Das Format allein beweist keinerlei Authentizität.
none ist nicht dasselbe wie „Base64URL kaputt“
Ich unterscheide:
- gültig dekodierbarer Header mit
alg: "none"; - leeres Signature-Segment;
- malformed JWT mit falscher Segmentzahl;
- signiertes JWT mit beschädigter Signatur.
Das sind verschiedene Fehlerklassen. Der JWT Decoder kann die Struktur sichtbar machen, aber Decoding ist keine Verifikation.
Warum dynamische Algorithmuswahl gefährlich ist
Ich schreibe nicht:
const algorithm = decodedHeader.alg;
verify(token, key, { algorithms: [algorithm] });
Denn dann beeinflusst untrusted Input direkt die Sicherheits-Policy. Stattdessen kommt die Allowlist aus Anwendungskonfiguration:
verify(token, trustedKey, {
algorithms: ["RS256"]
});
Wenn der Token none, HS256 oder etwas anderes behauptet, während die API RS256 erwartet, wird er abgelehnt.
Historische Fehlerklasse: Algorithmus-Verwechslung
Das grundlegende Problem hinter vielen JWT-Sicherheitsfehlern ist nicht nur none, sondern Algorithmus-Confusion: Der Verifier behandelt den Header als Vertrauensquelle und wählt dadurch einen Modus, den die Anwendung nie erlauben wollte.
RFC 8725 empfiehlt deshalb, erlaubte Algorithmen explizit festzulegen und sicherzustellen, dass sie zum verwendeten Schlüsseltyp passen.
Wann none überhaupt legitim sein kann
Unsecured JWTs existieren für spezielle Profile, in denen Integrität/Authentizität anderweitig garantiert wird oder bewusst nicht Bestandteil des JWT ist. Das ist eine explizite Protokollentscheidung.
Für meine normale Bearer-Access-Token-API gilt dagegen:
expected algorithms = RS256
received alg = none
=> reject
Ich aktiviere none niemals nur, weil ein fremdes Token sonst nicht durch die Verifikation kommt.
Was ich bei einem unerwarteten none-Token untersuche
- Kommt das Token vom erwarteten Issuer?
- Ist es überhaupt der erwartete Token-Typ?
- Hat eine Library oder ein Test-Tool ein unsigned Token erzeugt?
- Wurde Server-Verifikation versehentlich auf „decode only“ umgestellt?
- Ist Algorithmus-Allowlisting korrekt konfiguriert?
- Gibt es einen Test, der
alg: noneexplizit ablehnt?
Negative Tests, die ich in CI haben möchte
Für eine RS256-API teste ich mindestens:
RS256 + gültige Signatur -> accept (wenn Claims passen)
RS256 + falsche Signatur -> reject
HS256 statt RS256 -> reject
alg none + leere Signatur -> reject
unbekannter Algorithmus -> reject
manipulierter Payload -> reject
Damit prüfe ich die Sicherheitsgrenze und nicht nur den Happy Path.
typ und Token-Profil zusätzlich beachten
Selbst mit erlaubtem Algorithmus kann ein Token für einen anderen Zweck bestimmt sein. RFC 8725 behandelt explizite Typisierung und voneinander getrennte Validierungsregeln als wichtige Schutzmaßnahmen gegen Token-Verwechslung.
Ich prüfe daher neben alg auch iss, aud, Claims und gegebenenfalls typ/Profilregeln. Der JWT Validator verbindet Signatur- und Claim-Prüfung.
Entscheidungsmatrix
| Beobachtung | Bedeutung | Aktion |
|---|---|---|
alg=none, API erwartet RS256 | Policy-Verstoß | ablehnen |
alg=none, explizites unsecured Profil | profilabhängig | nur nach Spezifikation verarbeiten |
| Header sagt HS256, Config RS256 | Algorithm mismatch | ablehnen |
| leeres Signature-Segment bei signiertem Profil | keine Authentizität | ablehnen |
unbekannter alg | nicht erlaubter Modus | fail closed |
Mein sicherer alg-Workflow
- Ich definiere erlaubte Algorithmen aus vertrauenswürdiger Serverkonfiguration.
- Ich dekodiere den Header nur zur Diagnose.
- Ich vergleiche
algmit der Allowlist. - Ich prüfe, ob Algorithmus und Key-Typ zusammenpassen.
- Ich lehne
noneab, wenn das Profil Signatur verlangt. - Ich verifiziere mit dem vorgesehenen vertrauenswürdigen Key.
- Ich validiere danach
iss,aud, Zeit und Token-Typ. - Ich habe negative Tests für
none, Algorithmuswechsel und manipulierte Payloads.
Die sichere Regel ist einfach: Der Token Header beschreibt, was das Token behauptet. Die Anwendungskonfiguration entscheidet, was akzeptiert werden darf.