JSON Web Token (JWT) vorgestellt

Lange Zeit wurden für die Benutzerauthentifizierung im Web Cookies verwendet. Das funktioniert sehr gut, für bestimmte Anwendungen bis heute noch. Doch manchmal braucht man mehr Flexibilität. Hier kommen JSON Web Tokens ins Spiel. Als neuer, offener Standard werden sie zunehmend von wichtigen Webseiten und Anwendungen übernommen. Wir zeigen Ihnen, was ein JWT ist, wie es funktioniert und wo es eingesetzt wird.

Was ist ein JSON Web Token?

Ein JSON Web Token ist ein nach RFC 7519 genormtes Access Token und ermöglicht es, Daten sicher zwischen zwei Parteien auszutauschen. Es enthält dabei alle wichtigen Informationen über eine Entität, wodurch keine Datenbankabfrage erforderlich ist und die Sitzung nicht auf dem Server gespeichert werden muss (Stateless Session).

Besonders beliebt sind JSON Web Tokens daher bei Authentifizierungsvorgängen. Die kurzen Nachrichten können verschlüsselt werden und geben dann sicher darüber Auskunft, wer der Absender ist und ob dieser die benötigten Zugriffsrechte hat. Nutzer selbst kommen dabei nur indirekt mit dem Token in Kontakt – beispielsweise indem sie Benutzernamen und Passwort in einer Maske eintragen. Die eigentliche Kommunikation findet zwischen den verschiedenen Anwendungen auf Client- und Serverseite statt.

Wie ist ein JSON Web Token aufgebaut?

Ein signiertes JWT besteht aus drei Teilen, die jeweils mit Base64 kodiert werden und durch einen Punkt getrennt sind:

HEADER.PAYLOAD.SIGNATURE

Was bedeuten diese drei Teile?

Header

Der Header besteht meistens aus zwei Teilen und liefert wichtige Informationen über das Token. Er enthält den Typ des Tokens und den verwendeten Signatur- und/oder Verschlüsselungsalgorithmus. Ein Beispiel eines JWT-Headers kann wie folgt aussehen:

{ "alg": "HS256", "typ": "JWT" }

Als Typ ist immer JWT empfohlen. Es beschreibt den IANA Medientyp „application/jwt“. In dem oben genannten Beispiel gibt der Header an, dass HMAC-SHA256, abgekürzt mit „HS256“, zum Signieren des Tokens verwendet wird. Weitere typische Verschlüsselungsmethode sind RSA mit SHA-256 („RS256“) und ECDSA mit SHA-256 („ES256“). Nicht zu empfehlen ist es, keine Verschlüsselung zu verwenden. Sollten die Daten jedoch keinen hohen Schutzfaktor aufweisen, kann als Verschlüsselung „none“ angegeben werden. Mögliche Werte sind durch die JSON-Web-Encryption (JWE) nach RFC 7516 genormt.

Bei komplexer signierten oder verschlüsselten JSON Web Tokens gibt es zusätzlich den Parameter „cty“ für „Content Type“. Er wird ebenfalls mit dem Wert „JWT“ befüllt. In allen anderen Fällen wird dieser Parameter weggelassen.

Payload

Der Bereich Payload des JSON Web Tokens ist der Ort, der die tatsächlichen Informationen enthält, die an die Anwendung übermittelt werden sollen. Hierbei sind einige Standards definiert, die festlegen, was und wie bestimmte Daten übermittelt werden. Die Informationen sind als Key-/Value-Paare bereitgestellt, wobei die Schlüssel bei JWT als Claims bezeichnet werden. Es gibt drei unterschiedliche Typen von Claims:

  • Registrierte Claims sind Claims, die im IANA JSON Web Token Claim Register registriert und deren Zweck in einem Standard festgelegt sind. Einige Beispiele sind Aussteller des Tokens („iss“ für Issuer), Zieldomäne („aud“ für Audience) und Verfallszeit („exp“ für Expiration Time). Um die Länge des Tokens möglichst gering zu halten, wurden kurze Claim-Namen verwendet.
  • Öffentliche Claims sind nach Belieben definierbar. Es gibt hier also keine Einschränkungen. Damit keine Kollisionen bei der Semantik der Keys auftreten, ist es notwendig, die Claims im IANA-JSON-Web-Token-Claim-Register öffentlich zu registrieren oder kollisionsresistente Namen zu vergeben.
  • Private Claims sind für Informationen gedacht, die speziell mit der eigenen Anwendung ausgetauscht werden sollen. Während öffentliche Claims Informationen wie „Name“ oder „E-Mail“ enthalten, sind private Claims spezifischer. Eine typische Information ist beispielsweise eine „Benutzer-ID“ oder ein konkreter „Abteilungsname“. Wichtig ist es, bei der Namensgebung darauf zu achten, dass keine Kollision mit registrierten oder öffentlichen Claims entsteht.

Alle Claims sind optional. Man muss also nicht jeden registrierten Claim verwenden. Generell können Payloads beliebig viele Claims enthalten, es empfiehlt sich jedoch, die Informationen im JWT auf das Nötigste zu begrenzen. Je größer das JWT, desto mehr Ressourcen benötigt es bei der (De-)Kodierung.

Die Payload kann demnach folgendermaßen aufgebaut sein:

{ "sub": "123", "name": "Alice", "exp": 30 }

Signature

Die Signatur eines JSON Web Tokens wird unter Verwendung der Base64-Kodierung des Headers und Payloads und der angegebenen Signatur-/Verschlüsselungsmethode erstellt. Den Aufbau definiert die JSON Web Signature (JWS), ein nach RFC 7515 genormter Standard. Damit die Signatur funktioniert, ist es notwendig, einen geheimen Schlüssel zu verwenden, der nur der Ursprungsanwendung bekannt ist. Diese Signatur verifiziert zum einen, dass die Nachricht unterwegs nicht verändert wurde. Zum anderen stellt sie bei einem Token, das mit einem privaten Schlüssel signiert ist, sicher, dass der Absender des JWT auch der richtige ist.

Je nach Sensibilität der Daten gibt es unterschiedliche Verfahren:

  1. Keine Sicherung: Wie erwähnt kann bei einem geringen Schutzfaktor der Daten im Header der Wert „none“ angegeben werden. In diesem Fall wird keine Signatur generiert. Das JSON Web Token besteht also nur aus Header und Payload. Ohne Sicherung ist das Payload nach der Base64-Entschlüsselung im Klartext lesbar und es ist nicht verifiziert, ob die Nachricht vom richtigen Absender kommt oder sie unterwegs verändert wurde.
  2. Signatur (JWS): In der Regel reicht es aus zu prüfen, ob die Daten vom richtigen Absender kommen und ob sie verändert wurden. Hierfür kommt das Schema JSON Web Signature (JWS) zum Einsatz, das sicherstellt, dass die Nachricht unterwegs nicht verändert wurde und vom richtigen Absender kommt. Auch bei diesem Verfahren kann die Payload nach der Base64-Entschlüsselung im Klartext gelesen werden.
  3. Signatur (JWS) und Verschlüsselung (JWE): Es ist möglich, zusätzlich zur JWS eine JSON Web Encryption (JWE) einzusetzen. JWE verschlüsselt die Inhalte des Payloads, die anschließend mit JWS signiert werden. Um die Inhalte zu entschlüsseln, wird ein gemeinsames Kennwort oder ein privater Schlüssel angegeben. Der Absender ist also verifiziert, die Nachricht vertraulich und authentisch und die Payload nach der Base64-Entschlüsselung nicht im Klartext lesbar.

Durch die Verschlüsselung entsteht eine scheinbar zufällige Folge von Zeichen:

{ 7WK5T79u5mIzjIXXi2oI9Fglmgivv7RAJ7izyj9tUyQ }
Hinweis

Bei jedem der oben genannten Verfahren sollten Sie zusätzlich SSL für die Kommunikation nutzen, um die Daten zu schützen.

Wie funktioniert ein JSON Web Token?

Die Funktion des JSON Web Token lässt sich sehr gut anhand eines Benutzer-Logins erklären. Vor der Nutzung des JWT ist ein geheimer Schlüssel (secret) festzulegen. Sobald ein Benutzer erfolgreich seine Anmeldedaten eingegeben hat, wird das JWT mit dem Schlüssel zurückgegeben und lokal gespeichert. Die Übertragung sollte hierbei über HTTPS erfolgen, damit die Daten besser geschützt sind.

Immer wenn der Benutzer auf geschützte Ressourcen – z. B. auf eine API – oder einen geschützten Pfad zurückgreifen möchte, wird vom User Agent das JWT als Parameter (z. B. ‚jwt‘ bei GET-Requests) oder als Authorization Header (bei POST, PUT, OPTIONS, DELETE) gesendet. Der Kommunikationspartner kann das JSON Web Token entschlüsseln und bei erfolgreicher Überprüfung die Anfrage ausführen.

Hinweis

Da es sich beim JSON Web Token um Anmeldedaten handelt, sollten Sie das Token nicht länger als erforderlich aufbewahren und keine sensiblen Daten im Browser-Speicher ablegen.

Wo wird das JSON Web Token eingesetzt?

JSON Web Token bietet im Vergleich zur traditionellen Variante der Authentifizierung und Autorisierung mit Cookies einige Vorteile und wird deshalb u. a. für folgende Szenarien angewendet:

  1. REST-Anwendungen: Bei REST-Anwendungen sichert das JWT die Zustandslosigkeit, indem es Informationen für die Authentifikation direkt beim Request mitsendet.
  2. Cross-Origin Ressource Sharing: JSON Web Token sendet Informationen beim Cross-Origin Ressource Sharing. Das bringt einen enormen Vorteil gegenüber Cookies, die bei diesem Verfahren in der Regel nicht mitgesendet werden.
  3. Einsatz von mehreren Frameworks: JSON Web Token ist standardisiert und immer wieder einsetzbar. Bei der Verwendung von mehreren Frameworks lassen sich so einfacher Daten der Authentifikation teilen.

Wie sieht eine JWT-Beispiel-Implementierung in der Praxis aus?

Anhand eines JWT-Beispiels wollen wir Ihnen zeigen, wie das Token am Ende aussieht. Dazu nehmen wir den Beispiel-Header, den wir bereits am Anfang erwähnt haben:

{
	"alg": "HS256",
	"typ": "JWT"
}

Ein Beispiel für das Payload des JSON Web Token kann wie folgt aussehen:

{
	"sub": "0123456789",
	"name": "Max Mustermann",
	"admin": true
}

Um den tatsächlichen Aufbau des JWT (drei durch Punkte getrennte Teile) zu erreichen, müssen der Header und das Payload mit Base64 kodiert werden. Für den Header sieht das wie folgt aus:

base64Header = base64Encode(header)
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Genauso wird es für das Payload umgesetzt:

base64Payload = base64Encode(payload)
// eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

Jetzt muss noch die Signatur erstellt werden. Im Header haben wir angegeben, dass mit HMAC-SHA256 signiert wird:

signature = HS256(base64Header + '.' + base64Payload, 'secret')
// dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

Als letzten Schritt müssen diese drei Teile noch zusammengefügt und mit einem Punkt getrennt werden:

Token = base64Header + '.' + base64Payload + '.' + signature

// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

Die meisten Programmiersprachen stellen mittlerweile Bibliotheken zur Generierung von JSON Web Token bereit, sodass eine manuelle Umsetzung nicht mehr nötig ist.