Nutzer-Authentifizierung in Microservice-Umgebungen

Seite 2: JWT Flow im Detail

Inhaltsverzeichnis

Zunächst muss sich ein Nutzer beim Autorisierungsservice mit seinen Anmeldedaten einloggen. Da kann entweder per SSO oder klassischem Login passieren. Der Autorisierungsservice überprüft nun die Anmeldedaten und erstellt ein neues JWT. Der Code zum Erstellen eines JWT inklusive der Signiervorgang mit dem RS256-Algorithmus könnte in Java folgendermaßen aussehen:

public String createJwt(User loggedInUser) {
JwtBuilder builder = Jwts.builder()
.setSubject(loggedInUser.getUsername())
.claim("payload", loggedInUser.getPayload())
.setId(loggedInUser.getId())
.setExpiration(calculateExpirationTime());

return builder.signWith(
SignatureAlgorithm.RS256, privateKey
)
.compact();
}

Hier wird als Subject der Name des Nutzers und mit der claim-Methode der Payload des Nutzers für die Autorisierungsinformationen gesetzt. Danach legt das Programm eine eindeutige ID fest, anhand derer sich das Token jederzeit identifizieren lässt. Als Letztes definiert man ein Ablaufdatum.

Vor dem Zurückgeben des Token wird es noch mit dem Private Key signiert und in einen kompakten String serialisiert. Alle hier benutzten JWT-Methoden stammen aus dem Package io.jsonwebtoken, das sich bequem im Java-Projekt einbinden lässt. Libraries existieren für nahezu alle gängigen Programmiersprachen, sodass die Integration relativ einfach ist.

Nun kann die Anwendung das kompakte Token, das im folgenden Listing zu sehen ist, im Authorization Header des Browsers mitschicken, um sich gegenüber der Webseite zu authentifizieren – die einzelnen Teile des JWT sind mit Punkten getrennt – in der Form Header.Payload.Signatur:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Auf der Seite der Microservices ist nun die Signatur des Tokens zu prüfen, um zu sehen, dass es überhaupt valide ist. Das Ablaufdatum sollte natürlich auch überprüft werden. In Java ist das im Prinzip der folgende Programmcode:

Claims claims = Jwts.parser()
.setSigningKey(publicKey)
.parseClaimsJws(accesTokenString)
.getBody();

Der Parser verifiziert, dass das Token im gültigen Format vorliegt, und prüft in der parseClaimsJws-Methode, ob es korrekt signiert und noch gültig ist. Der Microservice kann jetzt davon ausgehen, dass der Nutzer legitim ist und ihn als vertrauenswürdig einstufen.

Ein veranschaulichter Auth-Flow zwischen Microservices (grün) und der UI (blau) (Abb. 5)

Nachdem gezeigt wurde, wie einfach sich ein JWT erstellen und auslesen lässt, sollten allerdings noch einige Rahmenbedingungen erläutert werden, die es einzuhalten gilt. Die Menge an Payload im Token darf eine gewisse Länge nicht überschreiten, um eine Limitierung durch den Browser oder Server zu vermeiden (Apache hat hier zum Beispiel ein Standardlimit von 8 KByte). Auch sollten Tokens ein Ablaufdatum haben, da ansonsten das Entziehen von Nutzerrechten nahezu unmöglich wird. Zu guter Letzt sollten sie keine sicherheitskritischen Informationen wie Passwörter enthalten. Diese wären lediglich mit Base64 kodiert und ließen sich somit von jedem User dekodieren und auslesen.

JWTs sind nicht die einzige Möglichkeit, Nutzer im Web- und Microservice-Kontext zu authentifizieren. Alternativ lässt sich die Security Assertion Markup Language (SAML) verwenden. Sie ist jedoch ein XML-Format und hat somit sprachbedingt ein deutlich umfangreicheres Datenvolumen, was sich vor allem auf mobilen Endgeräten negativ auswirkt. Dafür kann SAML mit asymmetrischen Signaturverfahren wie "Private Public Key Pair" agieren. Allerdings ist XML durch die digitale Signatur komplex und im Vergleich mit JSON schwieriger in Objekte umzuwandeln.

Eine weitere Möglichkeit sind Simple Web Tokens (SWT). Sie können allerdings nur durch symmetrische Signierungsverfahren geprüft werden. Das erhöht die Anfälligkeit für Hackerangriffe. Denn sobald ein Microservice gehackt ist, ist das Secret bekannt und das ganze System kompromittiert. Bei JWT kennt nur der Autorisierungsservice das Secret – und dieser einzelne Service lässt sich besser schützen als eine Vielzahl.

Im Vergleich zu anderen Optionen überwiegen bei JWT die Vorteile: die einfache Integrierbarkeit in viele Programmiersprachen, die zuverlässige Authentifizierung bei gleichzeitigem Reduzieren des Netzwerk-Overheads, die Nutzbarkeit im SSO-Fall sowie bei Login-Autorisierungen. Zusätzlich haben die JWTs verglichen mit SAML-Anwendungen den deutlich kleineren Footprint. JSON Web Tokens scheinen demnach für die Nutzer-Authentifizierung in einer Microservice-Umgebung die geeignetste Variante zu sein.

Weitere Informationen zu JSON Web Token finden sich auf der JWT-Website sowie im RFC7519.

Bernd Schönbach
ist seit über 10 Jahren in der Webentwicklung tätig. Zunächst in der PHP-Entwicklung im TYPO3-Umfeld. Mittlerweile entwickelt er mit Java Microservices.
(ane)