Skip to content
Zurück zum Blog
Sicherheit

JWT-Sicherheit: Best Practices, Angriffe und Abwehr (2026)

Sichern Sie Ihre JWTs: alg:none- und Algorithmus-Confusion-Angriffe stoppen, Algorithmen festlegen, Schlüssel rotieren, Claims prüfen und Token sicher speichern.

13 Min. Lesezeit

JWT-Sicherheit: Angriffe, Abwehr und eine Checkliste für 2026

JSON Web Tokens stecken heute hinter fast jeder modernen Authentifizierung. Trotzdem werden die Best Practices, die JWTs absichern, viel öfter übergangen, als sie sollten. JWT ist das De-facto-Format für Anmeldedaten bei OAuth 2.0, OpenID Connect und für Service-zu-Service-Aufrufe in Microservices. Und Jahr für Jahr produziert es einen steten Strom an CVEs, die fast alle auf dieselben vermeidbaren Fehler zurückgehen: unsignierte Token akzeptieren, dem vom Angreifer gewählten Algorithmus vertrauen, ein schwaches Signatur-Secret verwenden oder die Claim-Prüfung auslassen.

Ein JWT ist genau dann sicher, wenn vier Dinge gleichzeitig stimmen. Die Signatur ist intakt, der Angreifer kann den Algorithmus nicht austauschen, die Claims werden tatsächlich geprüft, und das Token liegt an einem Ort, von dem es sich nicht trivial stehlen lässt. Bricht auch nur eine dieser Bedingungen, haben Sie statt einer gehärteten API eine Authentifizierungsumgehung. Dieser Leitfaden geht zuerst die drei wichtigsten Angriffe durch und danach die Abwehr: einen Algorithmus wählen und festlegen, Schlüssel verwalten, Claims prüfen und Token speichern. Am Ende steht eine Checkliste, die Sie direkt in ein Review übernehmen können.

Wie eine JWT-Signatur Sie tatsächlich schützt (und was nicht)

Bevor ein Angriff überhaupt Sinn ergibt, müssen Sie eine Tatsache klar vor Augen haben: Ein JWT ist kodiert, nicht verschlüsselt. Ein signiertes Token besteht aus drei Base64URL-Segmenten, die Punkte trennen: header.payload.signature. Header und Payload sind schlichtes Base64URL von JSON. Wer das Token besitzt, kann jeden Claim darin lesen. Fügen Sie ein beliebiges Token in unseren JWT-Dekodierer ein, und Header sowie Payload erscheinen als lesbares JSON, ganz ohne Schlüssel. Die Payload ist von vornherein öffentlich.

Woher kommt also die Sicherheit? Von der Signatur, und nur von ihr. Das ist ein kryptografischer Wert, den HMAC mit einem Secret oder RSA bzw. ECDSA mit einem privaten Schlüssel über Header und Payload berechnet. Ein Angreifer kann ein Token frei lesen, aber ohne den Signaturschlüssel kein anderes Token erzeugen, das die Verifizierung besteht. An dieser einen Eigenschaft hängt das gesamte Vertrauensmodell.

Daraus folgen zwei Dinge. Erstens: Legen Sie niemals Geheimnisse in die Payload, also keine Passwörter, API-Schlüssel oder vollständigen personenbezogenen Daten. Sie ist für jeden lesbar, der das Token abfängt. Zweitens hängt Ihre gesamte Sicherheitslage an einem einzigen Schritt, nämlich die Signatur korrekt zu verifizieren. Genau diesen Schritt nehmen Angreifer ins Visier. Wenn Sie das Lesen von Token Segment für Segment ausführlicher nachvollziehen möchten, lesen Sie wie man ein JWT dekodiert.

Die 3 kritischen JWT-Angriffe (und wie Sie jeden stoppen)

Die meisten JWT-Schwachstellen sind Varianten desselben Musters: Der Server vertraut etwas, das der Angreifer kontrolliert. Hier sind die drei, die Authentifizierung komplett aushebeln, jeweils mit dem Mechanismus dahinter und der Lösung.

1. Der alg:none-Angriff: Umgehung über unsignierte Token

Die JWS-Spezifikation kennt für alg den Wert none, also „unsigniert”. Ein alg:none-Token hat ein leeres Signatursegment und endet trotzdem mit einem abschließenden Punkt, etwa header.payload.. Der Angriff ist simpel: Nehmen Sie ein gültiges Token, ändern Sie im Header alg auf none, tauschen Sie beliebige Claims ein (etwa "role": "admin") und lassen Sie die Signatur weg. Frühe JWT-Bibliotheken akzeptierten das standardmäßig, sodass das gefälschte Token problemlos durch die Verifizierung kam. Kein Schlüssel, keine Signatur, volle Identitätsübernahme.

Wie ein solches Token aussieht, sehen Sie, indem Sie das Beispiel „alg:none” in unserem JWT-Dekodierer laden. Er zeigt eine rote Warnung an, dass das Token unsigniert ist und niemals für die Authentifizierung akzeptiert werden darf. So ein Token selbst nachzubauen dauert eine Minute und hilft, die Bedrohung zu begreifen.

Die Abwehr ist eine explizite Algorithmus-Allowlist bei jedem Verify-Aufruf. Überlassen Sie der Bibliothek nie die Entscheidung, was akzeptabel ist. Ältere Standardeinstellungen waren freizügig, und der Preis für Explizitheit ist eine einzige zusätzliche Option.

// WRONG — the library may accept alg:none or any algorithm
jwt.verify(token, key);

// RIGHT — pin the exact algorithm you expect
jwt.verify(token, key, { algorithms: ['RS256'] });

none sollte in diesem Array niemals auftauchen. Wenn Ihre Bibliothek Algorithmen nicht festlegen kann, ersetzen Sie sie.

2. Algorithmus-Confusion: RS256 auf HS256 herabgestuft

In der Praxis ist das die gefährlichste JWT-Schwachstelle, bekannt seit 2015 und bis heute in Audits zu finden. Sie nutzt Server aus, die das Wie der Verifizierung am alg-Feld im Header festmachen, also genau an dem Token-Teil, den ein Angreifer umschreiben kann.

So läuft der Mechanismus ab. Ihr Server stellt RS256-Token aus: Er signiert mit einem privaten RSA-Schlüssel und verifiziert mit dem passenden öffentlichen Schlüssel. Dieser öffentliche Schlüssel ist per Definition öffentlich und liegt vielleicht in Ihrem JWKS-Endpunkt oder Ihrem Repository. Der Angreifer nimmt ihn, ändert den Token-Header von RS256 auf HS256 und signiert eine gefälschte Payload per HMAC-SHA256, wobei er die Zeichenkette des öffentlichen Schlüssels als HMAC-Secret nutzt. Auf der Verifizierungsseite passiert nun Folgendes: Liest Ihr Code alg aus dem Header und wählt entsprechend HMAC, berechnet er HMAC-SHA256 über das Token mit ebendiesem öffentlichen Schlüssel als Secret. Die Signaturen stimmen überein. Das gefälschte Token wird akzeptiert.

Die Ursache liegt im Zusammentreffen zweier Tatsachen: Der Verifizierer vertraute dem vom Angreifer kontrollierten alg-Header, und der öffentliche RSA-Schlüssel stand dem Angreifer als HMAC-Schlüssel zur Verfügung. Für sich genommen ist keine der beiden ein Fehler. Ein öffentlicher Schlüssel soll öffentlich sein, und ein alg-Header soll das Token beschreiben. Gefährlich wird es erst, wenn Ihre Verifizierungslogik diesen Header bestimmen lässt, welcher Schlüsseltyp und Algorithmus verwendet wird. Dann steuert ein Wert, den der Angreifer schreibt, den Krypto-Pfad, den der Server ausführt.

// WRONG — verification method follows the header's alg field
jwt.verify(token, publicKeyOrSecret);

// RIGHT — hard-code the expected algorithm; never let the header choose
jwt.verify(token, publicKey, { algorithms: ['RS256'] });

Legen Sie den asymmetrischen Algorithmus explizit fest (nur RS256 oder ES256), halten Sie die HMAC-Verifizierung auf einem komplett getrennten Code-Pfad von der RSA-Verifizierung, und nutzen Sie eine gepflegte Bibliothek, die Schlüsseltypen unterscheidet. Unser JWT-Dekodierer markiert jedes Token der HS-Familie mit einer Public-Key-Confusion-Warnung, gerade weil dieser Angriff so verbreitet ist. Wenn ein Token, das Sie als asymmetrisch erwartet hatten, als HS256 auftaucht, ist diese Warnung Ihr Signal.

3. Schwaches HMAC-Secret: Brute-Force- und Wörterbuchangriffe

Wenn Sie HMAC einsetzen (HS256/384/512), ruht die gesamte Sicherheit des Tokens auf der Entropie eines einzigen Secrets. Ist dieses Secret kurz, ein Wörterbuchwort oder ein Wert wie secret oder password123, kann ein Angreifer es offline knacken, sobald er ein einziges gültiges Token abgreift. Werkzeuge wie hashcat prüfen Milliarden Kandidaten pro Sekunde gegen die Signatur des Tokens. Sobald das Secret fällt, kann der Angreifer jedes beliebige Token ausstellen, also gültige admin-Anmeldedaten für immer.

Was diesen Angriff so leise gefährlich macht: Er läuft vollständig offline. Der Angreifer hämmert nicht auf Ihren Login-Endpunkt ein, also schlägt kein Rate-Limit an und in Ihren Logs ist nichts zu sehen. Er greift ein Token ab, knackt das Secret auf eigener Hardware und kehrt erst zurück, wenn er Token signieren kann, die jede Ihrer Prüfungen bestehen. Die Lösung ist nicht verhandelbar: Verwenden Sie mindestens 32 zufällige Bytes (256 Bit) aus einer kryptografisch sicheren Quelle und legen Sie sie in einem Secrets-Manager ab, nie im Code oder im Repository.

// WRONG — guessable, low entropy, crackable in seconds
const secret = "password123";

// RIGHT — 256 bits from a CSPRNG, then load from KMS at runtime
const secret = require('crypto').randomBytes(32).toString('base64');

Brauchen Sie schnell einen starken Wert, erzeugt unser Zufallspasswort-Generator Zeichenketten mit hoher Entropie, die sich als HMAC-Schlüssel eignen. Den Unterschied spüren Sie praktisch, wenn Sie ein Testtoken mit einem starken Secret in unserem JWT-Kodierer signieren, der vollständig im Browser läuft, sodass das Secret Ihren Rechner nie verlässt. Und sobald die Verifizierung eine Vertrauensgrenze überschreitet, etwa über mehrere Services oder Drittanbieter-Verifizierer, verzichten Sie ganz auf HS256 und wechseln Sie zu einem asymmetrischen Algorithmus, wie als Nächstes beschrieben.

Den richtigen Algorithmus wählen und festlegen

An der Algorithmuswahl entscheidet sich, ob der Confusion-Angriff gewonnen oder verloren wird. Wählen Sie also bewusst. Die drei, die Sie tatsächlich verwenden werden:

AlgorithmusTypSchlüssel zum Signieren / VerifizierenWann verwenden
HS256Symmetrisch (HMAC)Ein gemeinsames SecretEine Vertrauensgrenze, dieselbe Partei signiert und verifiziert
RS256Asymmetrisch (RSA)Privater Schlüssel signiert / öffentlicher verifiziertService-übergreifend, Drittanbieter-Verifizierung, JWKS-Rotation
ES256Asymmetrisch (ECDSA)Privater Schlüssel signiert / öffentlicher verifiziertWie RS256, kleinere und schnellere Schlüssel, für neue Systeme zu bevorzugen

Die Regel ist kurz. Signiert und verifiziert dieselbe Partei innerhalb einer Vertrauensgrenze, ist HS256 in Ordnung und schnell. Muss jemand anderes als der Signierende verifizieren, etwa ein anderer Service, ein Partner oder ein öffentlicher Client, verwenden Sie einen asymmetrischen Algorithmus und bevorzugen Sie ES256: Seine Schlüssel und Signaturen sind bei gleicher Stärke weit kleiner als bei RSA. Im JWT-Kodierer können Sie Beispiel-Token mit HS256, RS256 und ES256 nebeneinander signieren, um Struktur und Signaturlänge zu vergleichen.

Was auch immer Sie wählen, die Abwehr, auf die es wirklich ankommt, bleibt dieselbe: Legen Sie beim Verify-Aufruf ein explizites Algorithmus-Set fest und vertrauen Sie nie dem alg-Feld im Header. Die Allowlist ist das Fundament, auf dem alles andere ruht.

Schlüsselverwaltung und Rotation

Algorithmen sind nur so sicher wie die Schlüssel dahinter, und beim Umgang mit Schlüsseln werden die meisten Leitfäden schweigsam. Bei HS256 besteht das Secret aus mindestens 32 zufälligen Bytes und liegt in einem Secrets-Manager wie AWS Secrets Manager, HashiCorp Vault oder Azure Key Vault. Bei asymmetrischen Algorithmen gehört der private Schlüssel in ein HSM oder KMS und berührt nie Anwendungscode; der öffentliche Schlüssel wird veröffentlicht, typischerweise über einen JWKS-Endpunkt, den Verifizierer abrufen.

Rotation muss Routine sein, kein Notfall. Versehen Sie jeden Schlüssel mit einer kid (Key ID) im JWT-Header, damit Verifizierer wissen, welcher Schlüssel ein bestimmtes Token signiert hat. Halten Sie auf der Verifizierungsseite eine kleine Menge gültiger Schlüssel vor, den aktuellen plus den zuletzt vorherigen, damit Token, die kurz vor einer Rotation signiert wurden, während ihrer Lebensdauer noch verifizieren. Dank dieser Überlappung wird die Rotation nicht zum Ausfall.

Eine kurze Checkliste für Schlüssel:

  • Rotieren Sie Signaturschlüssel mindestens alle 90 Tage und sofort bei jedem Verdacht auf Kompromittierung.
  • Veröffentlichen Sie öffentliche Schlüssel über JWKS; versionieren Sie sie mit kid.
  • Halten Sie private Schlüssel und HMAC-Secrets in einem KMS oder HSM, nie in Git, nie im Client-Code, nie hartcodiert.
  • Bei einem Leck: Schlüssel rotieren und ausstehende Refresh-Token sofort widerrufen.

Claim-Prüfung, die Sie nicht auslassen dürfen

Die Signaturprüfung belegt, dass ein Token echt ist. Sie belegt nicht, dass das Token für Sie, gerade jetzt gilt. Das ist die Aufgabe der Claim-Prüfung, und sie ist die billigste Abwehr, die Sie ergänzen können. Diese fünf Claims sollten Sie bei jeder Anfrage prüfen:

  • exp (Ablauf) – Token ablehnen, deren Ablauf in der Vergangenheit liegt.
  • nbf (not before) – Token ablehnen, die vor Öffnung ihres Gültigkeitsfensters verwendet werden.
  • iat (issued at) – optional Token ablehnen, die unplausibel alt sind.
  • iss (Aussteller) – bestätigen, dass das Token vom Aussteller stammt, dem Sie vertrauen.
  • aud (Zielgruppe) – bestätigen, dass das Token für Ihren Service ausgestellt wurde. Eine fehlende aud-Prüfung ist das häufigste stille Loch und erlaubt, ein für eine API ausgestelltes Token gegen eine andere wiederzuverwenden.

Die meisten Bibliotheken prüfen das für Sie, wenn Sie die erwarteten Werte übergeben:

jwt.verify(token, key, {
  algorithms: ['ES256'],
  issuer: 'https://auth.example.com',
  audience: 'api.example.com',
  clockTolerance: 5, // seconds, for distributed clock skew
});

Erlauben Sie eine kleine Uhren-Toleranz, fünf Sekunden sind üblich, damit geringfügige Abweichungen zwischen Servern sonst gültige Token nicht ablehnen. Widerstehen Sie der Versuchung, sie größer zu machen; eine großzügige Toleranz weitet das Zeitfenster, in dem ein abgelaufenes Token noch funktioniert, also genau das, was exp schließen soll. Um die Werte exp und iat eines Tokens kurz mit dem Auge zu prüfen, fügen Sie es in den JWT-Dekodierer ein und wandeln Sie die Zeitstempel mit unserem Unix-Zeitstempel-Konverter um.

Token-Lebensdauer und wo JWTs gespeichert werden

Serverseitige Prüfungen sind nur die halbe Geschichte. Wo der Client das Token aufbewahrt, entscheidet darüber, wie leicht es sich stehlen lässt, und beim Speichern treffen XSS und Session-Hijacking aufeinander. Das Muster, das standhält: ein kurzlebiges Access-Token (15 bis 60 Minuten) gepaart mit einem separaten, längerlebigen Refresh-Token, das sich widerrufen lässt.

Die Speicherentscheidung läuft auf einen einzigen Kompromiss hinaus:

SpeicherortXSS-RisikoCSRF-RisikoEmpfehlung
localStorageHoch, jedes JavaScript auf der Seite kann es lesenKeinesFür Session-Token vermeiden
HttpOnly + Secure + SameSite=Strict CookieNiedrig, für JavaScript unsichtbarBraucht CSRF-SchutzFür Sessions empfohlen

Ein Token in localStorage ist von jedem Skript lesbar, das auf der Seite läuft, sodass ein einziger XSS-Fehler die gesamte Session preisgibt und der Angreifer sie über deren ganze Lebensdauer von seinem eigenen Rechner aus wiedergeben kann. Ein HttpOnly-Cookie kann JavaScript überhaupt nicht lesen, was den Schaden eines XSS auf das beschränkt, was ein Angreifer innerhalb einer lebenden Seite tun kann. Das ist schlimm, aber er kann keine Anmeldedaten stehlen und mitnehmen. Der Preis des Cookie-Ansatzes ist, dass Sie nun CSRF-Schutz brauchen, da Cookies bei jeder Anfrage automatisch mitreisen; SameSite=Strict plus ein CSRF-Token erledigt das. Halten Sie das Access-Token kurz, damit ein Leck einen kleinen Wirkungsradius hat, und legen Sie das Refresh-Token in ein HttpOnly-, Secure-, SameSite-Cookie. Beim Logout oder vermutetem Kompromiss widerrufen Sie das Refresh-Token serverseitig und rotieren Sie den Signaturschlüssel. Für den größeren Kontext rund um XSS, CSRF und sichere Cookies lesen Sie unseren Leitfaden zu Best Practices für Web-Sicherheit.

JWT-Sicherheits-Checkliste

Gehen Sie das durch, bevor Sie eine JWT-basierte Authentifizierung ausliefern:

  • Die Verifizierung legt eine explizite Algorithmus-Allowlist fest und lehnt alg:none ab.
  • Die asymmetrische Verifizierung codiert den erwarteten Algorithmus fest und liest alg nie aus dem Header (blockiert Confusion).
  • HS256-Secrets bestehen aus mindestens 32 zufälligen Bytes, geladen aus einem KMS.
  • Private Schlüssel liegen in einem HSM/KMS; öffentliche Schlüssel werden über JWKS veröffentlicht und mit kid versioniert.
  • Signaturschlüssel rotieren mindestens alle 90 Tage.
  • Jede Anfrage prüft exp, nbf, iat, iss und aud, mit einer Uhren-Toleranz von 5 Sekunden oder weniger.
  • Access-Token gelten 15 bis 60 Minuten; Refresh-Token liegen in einem HttpOnly-Cookie.
  • Keine Geheimnisse in der Payload, denn sie ist kodiert, nicht verschlüsselt.

FAQ

Ist JWT standardmäßig sicher?

Nein. JWT-Sicherheit hängt von der Konfiguration ab. Sie müssen den Algorithmus festlegen, alg:none ablehnen, ein Secret oder einen Schlüssel mit hoher Entropie verwenden und Claims prüfen. Standard- oder freizügige Bibliothekssetups erlauben häufig Authentifizierungsumgehungen.

Was ist die gefährlichste JWT-Schwachstelle?

Algorithmus-Confusion, bei der RS256 auf HS256 herabgestuft und der öffentliche Schlüssel als HMAC-Secret genutzt wird. Sie ist seit 2015 bekannt und taucht dennoch in Audits auf, weil sie Server ausnutzt, die die Verifizierungsmethode aus dem alg-Feld des Headers wählen.

Sollte ich HS256 oder RS256 verwenden?

Verwenden Sie HS256, wenn dieselbe Partei innerhalb einer Vertrauensgrenze signiert und verifiziert. Verwenden Sie RS256 oder ES256, wenn ein anderer Service oder ein Dritter verifizieren muss oder wenn Sie JWKS-Rotation brauchen. Für neue Systeme ist ES256 vorzuziehen: kleinere, schnellere Schlüssel bei gleicher Stärke.

Wo sollte ich ein JWT speichern?

Bevorzugen Sie für Session-Token ein HttpOnly-, Secure-, SameSite-Cookie, da JavaScript es nicht lesen und ein einziger XSS-Fehler es nicht stehlen kann. Vermeiden Sie localStorage für Session-Token, denn jedes XSS gibt die gesamte Session zur Wiedergabe preis.

Wie oft sollte ich JWT-Signaturschlüssel rotieren?

Rotieren Sie routinemäßig mindestens alle 90 Tage und sofort bei jedem vermuteten Kompromiss. Versionieren Sie Schlüssel mit kid und halten Sie sowohl den aktiven als auch den zuletzt vorherigen Schlüssel auf dem Verifizierer vor, damit kurz vor der Rotation signierte Token noch gültig sind.

Kann ein JWT manipuliert werden?

Nicht ohne den Signaturschlüssel; kein Angreifer kann ein Token fälschen, das die Verifizierung besteht. Aber wenn Ihr Server alg:none akzeptiert, für Algorithmus-Confusion anfällig ist oder ein schwaches Secret verwendet, lässt sich die Signatur umgehen. Das sind Konfigurationsfehler, keine Mängel von JWT selbst.

Welche Claims muss ich prüfen?

Prüfen Sie exp (Ablauf), nbf (not before), iat (issued at), iss (Aussteller) und aud (Zielgruppe). Eine fehlende aud-Prüfung ist die häufigste stille Schwachstelle und erlaubt, ein für einen Service bestimmtes Token gegen einen anderen wiederzuverwenden.

Fazit

JWT-Sicherheit ist nicht kompliziert, aber jede Schicht muss halten. Die Signatur ist Ihre einzige Garantie, also verifizieren Sie sie korrekt. Legen Sie einen einzigen expliziten Algorithmus fest und vertrauen Sie nie dem alg des Headers. Verwenden Sie starke, rotierte Schlüssel, die in einem KMS liegen. Prüfen Sie exp, nbf, iat, iss und aud bei jeder Anfrage. Speichern Sie Token dort, wo XSS sie nicht erreicht.

Um es in die Praxis umzusetzen, fügen Sie ein beliebiges Token in unseren JWT-Dekodierer ein, um Algorithmus und Claims zu inspizieren und alg:none- oder HS-Confusion-Risiken zu erkennen, und nutzen Sie den JWT-Kodierer, um das Signieren vollständig in Ihrem Browser auszuprobieren. Ihre Schlüssel verlassen Ihr Gerät dabei nie.

Tags: jwt security authentication oauth api-security

Verwandte Artikel

Alle Artikel anzeigen