Lange Zeit wurden für die Be­nut­zer­au­then­ti­fi­zie­rung im Web Cookies verwendet. Das funk­tio­niert sehr gut, für bestimmte An­wen­dun­gen bis heute noch. Doch manchmal braucht man mehr Fle­xi­bi­li­tät. Hier kommen JSON Web Tokens ins Spiel. Als neuer, offener Standard werden sie zunehmend von wichtigen Webseiten und An­wen­dun­gen über­nom­men. Wir zeigen Ihnen, was ein JWT ist, wie es funk­tio­niert und wo es ein­ge­setzt wird.

Was ist ein JSON Web Token?

Ein JSON Web Token ist ein nach RFC 7519 genormtes Access Token und er­mög­licht es, Daten sicher zwischen zwei Parteien aus­zu­tau­schen. Es enthält dabei alle wichtigen In­for­ma­tio­nen über eine Entität, wodurch keine Da­ten­bank­ab­fra­ge er­for­der­lich ist und die Sitzung nicht auf dem Server ge­spei­chert werden muss (Stateless Session).

Besonders beliebt sind JSON Web Tokens daher bei Au­then­ti­fi­zie­rungs­vor­gän­gen. Die kurzen Nach­rich­ten können ver­schlüs­selt werden und geben dann sicher darüber Auskunft, wer der Absender ist und ob dieser die be­nö­tig­ten Zu­griffs­rech­te hat. Nutzer selbst kommen dabei nur indirekt mit dem Token in Kontakt – bei­spiels­wei­se indem sie Be­nut­zer­na­men und Passwort in einer Maske eintragen. Die ei­gent­li­che Kom­mu­ni­ka­ti­on findet zwischen den ver­schie­de­nen An­wen­dun­gen auf Client- und Ser­ver­sei­te statt.

Wie ist ein JSON Web Token aufgebaut?

Ein si­gnier­tes 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 In­for­ma­tio­nen über das Token. Er enthält den Typ des Tokens und den ver­wen­de­ten Signatur- und/oder Ver­schlüs­se­lungs­al­go­rith­mus. Ein Beispiel eines JWT-Headers kann wie folgt aussehen:

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

Als Typ ist immer JWT empfohlen. Es be­schreibt den IANA Medientyp „ap­pli­ca­ti­on/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 Ver­schlüs­se­lungs­me­tho­de sind RSA mit SHA-256 („RS256“) und ECDSA mit SHA-256 („ES256“). Nicht zu empfehlen ist es, keine Ver­schlüs­se­lung zu verwenden. Sollten die Daten jedoch keinen hohen Schutz­fak­tor aufweisen, kann als Ver­schlüs­se­lung „none“ angegeben werden. Mögliche Werte sind durch die JSON-Web-En­cryp­ti­on (JWE) nach RFC 7516 genormt.

Bei komplexer si­gnier­ten oder ver­schlüs­sel­ten JSON Web Tokens gibt es zu­sätz­lich den Parameter „cty“ für „Content Type“. Er wird ebenfalls mit dem Wert „JWT“ befüllt. In allen anderen Fällen wird dieser Parameter weg­ge­las­sen.

Payload

Der Bereich Payload des JSON Web Tokens ist der Ort, der die tat­säch­li­chen In­for­ma­tio­nen enthält, die an die Anwendung über­mit­telt werden sollen. Hierbei sind einige Standards definiert, die festlegen, was und wie bestimmte Daten über­mit­telt werden. Die In­for­ma­tio­nen sind als Key-/Value-Paare be­reit­ge­stellt, wobei die Schlüssel bei JWT als Claims be­zeich­net werden. Es gibt drei un­ter­schied­li­che Typen von Claims:

  • Re­gis­trier­te Claims sind Claims, die im IANA JSON Web Token Claim Register re­gis­triert und deren Zweck in einem Standard fest­ge­legt sind. Einige Beispiele sind Aus­stel­ler des Tokens („iss“ für Issuer), Ziel­do­mä­ne („aud“ für Audience) und Ver­falls­zeit („exp“ für Ex­pi­ra­ti­on Time). Um die Länge des Tokens möglichst gering zu halten, wurden kurze Claim-Namen verwendet.
  • Öf­fent­li­che Claims sind nach Belieben de­fi­nier­bar. Es gibt hier also keine Ein­schrän­kun­gen. Damit keine Kol­li­sio­nen bei der Semantik der Keys auftreten, ist es notwendig, die Claims im IANA-JSON-Web-Token-Claim-Register öf­fent­lich zu re­gis­trie­ren oder kol­li­si­ons­re­sis­ten­te Namen zu vergeben.
  • Private Claims sind für In­for­ma­tio­nen gedacht, die speziell mit der eigenen Anwendung aus­ge­tauscht werden sollen. Während öf­fent­li­che Claims In­for­ma­tio­nen wie „Name“ oder „E-Mail“ enthalten, sind private Claims spe­zi­fi­scher. Eine typische In­for­ma­ti­on ist bei­spiels­wei­se eine „Benutzer-ID“ oder ein konkreter „Ab­tei­lungs­na­me“. Wichtig ist es, bei der Na­mens­ge­bung darauf zu achten, dass keine Kollision mit re­gis­trier­ten oder öf­fent­li­chen Claims entsteht.

Alle Claims sind optional. Man muss also nicht jeden re­gis­trier­ten Claim verwenden. Generell können Payloads beliebig viele Claims enthalten, es empfiehlt sich jedoch, die In­for­ma­tio­nen im JWT auf das Nötigste zu begrenzen. Je größer das JWT, desto mehr Res­sour­cen benötigt es bei der (De-)Kodierung.

Die Payload kann demnach fol­gen­der­ma­ßen aufgebaut sein:

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

Signature

Die Signatur eines JSON Web Tokens wird unter Ver­wen­dung der Base64-Kodierung des Headers und Payloads und der an­ge­ge­be­nen Signatur-/Ver­schlüs­se­lungs­me­tho­de erstellt. Den Aufbau definiert die JSON Web Signature (JWS), ein nach RFC 7515 genormter Standard. Damit die Signatur funk­tio­niert, ist es notwendig, einen geheimen Schlüssel zu verwenden, der nur der Ur­sprungs­an­wen­dung bekannt ist. Diese Signatur ve­ri­fi­ziert 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 Sen­si­bi­li­tät der Daten gibt es un­ter­schied­li­che Verfahren:

  1. Keine Sicherung: Wie erwähnt kann bei einem geringen Schutz­fak­tor 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-Ent­schlüs­se­lung im Klartext lesbar und es ist nicht ve­ri­fi­ziert, 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 si­cher­stellt, dass die Nachricht unterwegs nicht verändert wurde und vom richtigen Absender kommt. Auch bei diesem Verfahren kann die Payload nach der Base64-Ent­schlüs­se­lung im Klartext gelesen werden.
  3. Signatur (JWS) und Ver­schlüs­se­lung (JWE): Es ist möglich, zu­sätz­lich zur JWS eine JSON Web En­cryp­ti­on (JWE) ein­zu­set­zen. JWE ver­schlüs­selt die Inhalte des Payloads, die an­schlie­ßend mit JWS signiert werden. Um die Inhalte zu ent­schlüs­seln, wird ein ge­mein­sa­mes Kennwort oder ein privater Schlüssel angegeben. Der Absender ist also ve­ri­fi­ziert, die Nachricht ver­trau­lich und au­then­tisch und die Payload nach der Base64-Ent­schlüs­se­lung nicht im Klartext lesbar.

Durch die Ver­schlüs­se­lung entsteht eine scheinbar zufällige Folge von Zeichen:

{ 7WK5T79u5mIzjIXXi2oI9Fglmgivv7RAJ7izyj9tUyQ }
Hinweis

Bei jedem der oben genannten Verfahren sollten Sie zu­sätz­lich SSL für die Kom­mu­ni­ka­ti­on nutzen, um die Daten zu schützen.

Wie funk­tio­niert 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) fest­zu­le­gen. Sobald ein Benutzer er­folg­reich seine An­mel­de­da­ten ein­ge­ge­ben hat, wird das JWT mit dem Schlüssel zu­rück­ge­ge­ben und lokal ge­spei­chert. Die Über­tra­gung sollte hierbei über HTTPS erfolgen, damit die Daten besser geschützt sind.

Immer wenn der Benutzer auf ge­schütz­te Res­sour­cen – z. B. auf eine API – oder einen ge­schütz­ten Pfad zu­rück­grei­fen möchte, wird vom User Agent das JWT als Parameter (z. B. ‚jwt‘ bei GET-Requests) oder als Aut­ho­riza­ti­on Header (bei POST, PUT, OPTIONS, DELETE) gesendet. Der Kom­mu­ni­ka­ti­ons­part­ner kann das JSON Web Token ent­schlüs­seln und bei er­folg­rei­cher Über­prü­fung die Anfrage ausführen.

Hinweis

Da es sich beim JSON Web Token um An­mel­de­da­ten handelt, sollten Sie das Token nicht länger als er­for­der­lich auf­be­wah­ren und keine sensiblen Daten im Browser-Speicher ablegen.

Wo wird das JSON Web Token ein­ge­setzt?

JSON Web Token bietet im Vergleich zur tra­di­tio­nel­len Variante der Au­then­ti­fi­zie­rung und Au­to­ri­sie­rung mit Cookies einige Vorteile und wird deshalb u. a. für folgende Szenarien an­ge­wen­det:

  1. REST-An­wen­dun­gen: Bei REST-An­wen­dun­gen sichert das JWT die Zu­stands­lo­sig­keit, indem es In­for­ma­tio­nen für die Au­then­ti­fi­ka­ti­on direkt beim Request mitsendet.
  2. Cross-Origin Ressource Sharing: JSON Web Token sendet In­for­ma­tio­nen beim Cross-Origin Ressource Sharing. Das bringt einen enormen Vorteil gegenüber Cookies, die bei diesem Verfahren in der Regel nicht mit­ge­sen­det werden.
  3. Einsatz von mehreren Frame­works: JSON Web Token ist stan­dar­di­siert und immer wieder ein­setz­bar. Bei der Ver­wen­dung von mehreren Frame­works lassen sich so einfacher Daten der Au­then­ti­fi­ka­ti­on teilen.

Wie sieht eine JWT-Beispiel-Im­ple­men­tie­rung 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 tat­säch­li­chen 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 zu­sam­men­ge­fügt und mit einem Punkt getrennt werden:

Token = base64Header + '.' + base64Payload + '.' + signature
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

Die meisten Pro­gram­mier­spra­chen stellen mitt­ler­wei­le Bi­blio­the­ken zur Ge­ne­rie­rung von JSON Web Token bereit, sodass eine manuelle Umsetzung nicht mehr nötig ist.

Zum Hauptmenü