CodeGym /Kurse /Spring Security /JWT in stateless API

JWT in stateless API

Spring Security
Level 22, Lektion 0
Verfügbar

1. JWT in einem Satz: Was es ist und was nicht

Wenn Sie JWT zum ersten Mal sehen, sieht es ungefähr aus wie ein Wi‑Fi-Passwort, das jemand von der Decke abgeschrieben hat: viele Zeichen, Punkte, unverständliche Magie. Aber der kürzeste und ehrlichste Blick auf JWT lautet: JWT ist ein kompakter String, der eine kleine Menge von Daten (Claims) zwischen Anfragen überträgt und durch eine Signatur vor unbemerkter Manipulation geschützt wird. Das ist alles – nicht mehr und nicht weniger.

Sobald der Server aufhört, die Session zu speichern und sich den Benutzer zwischen Anfragen zu merken, taucht eine neue technische Frage auf: Was wird der Client anstelle des serverseitigen Speichers mitbringen, um bei jeder Anfrage die Authentifizierung wiederherstellen zu können? JWT taucht genau hier auf.

Probleme beginnen, wenn JWT als „neues Sicherheitsmodell“ oder „Ersatz für den gesamten Server“ wahrgenommen wird. JWT ist nicht Spring Security und nicht einmal „Autorisierung“. Es entscheidet nicht für Sie, ob ein Benutzer einen Entwurf veröffentlichen darf. Es ersetzt nicht Ihre @PreAuthorize-Regeln, weiß nichts über Ownership und kann automatisch weder 401 von 403 unterscheiden. Es hilft lediglich, das zu übermitteln, was der Server wissen muss, um diese Entscheidungen zu treffen.

Es ist sehr hilfreich, eine einfache Unterscheidungstabelle im Kopf zu behalten – nicht als Prüfungszusammenfassung, sondern als Gegenmittel gegen zwei verbreitete Illusionen.

Was ist das Worum geht es Was gibt es Was gibt es nicht
JWT als Format Struktur des Tokens und Feldset Bequeeme tragbare „Datenkarte“ Automatische Sicherheit „aufgrund des bloßen Vorhandenseins des Tokens“
Signatur des JWT Datenintegrität Schutz vor unbemerkter Manipulation des Payload Geheimhaltung des Payload (er ist lesbar)
Sicherheitsmodell der Anwendung Zugriffsregeln und Lebenszyklus Wer hat Zugriff worauf, wie werden Fehler behandelt Kann nicht durch eine einzelne Token-Zeile „ersetzt“ werden

Hier möchte man einen Scherz machen, aber der Scherz liegt bereits darin, wie oft JWT zum „König aller Probleme“ ernannt wird. JWT ist wie ein Reisepass. Ein Reisepass hilft, eine Person zu identifizieren und trägt einen gewissen Kontext. Aber ein Reisepass bewacht nicht von allein ein Museum, schließt keine Türen und entscheidet nicht, ob Sie in die Gemäldegalerie dürfen. Das Museum entscheidet das durch Regeln, Sicherheitspersonal und Drehkreuze. JWT ist in unserer Anwendung ein ebensolches „Dokument“, kein „Wächter“.

2. Stateless API und das „Übertragen von Gedächtnis“ zwischen Anfragen

In der session-basierten Welt war alles recht gemütlich. Der Benutzer loggte sich einmal ein, der Server legte den benötigten Security-Kontext in die Session, der Client trug ein Cookie, und die weiteren Anfragen wirkten wie eine „Fortsetzung des Gesprächs“. Die stateless Welt gleicht eher einer Situation „bei jedem Eintritt – Ausweiskontrolle“. Der Server speichert „Ihre Karte“ nicht zwischen Anfragen, daher muss der Client jedes Mal einen Nachweis darüber mitbringen, wer er ist.

Und hier ist es leicht, zwei Dinge zu verwechseln: Credentials und Token. Credentials sind das, womit der Benutzer beim Login seine Identität nachweist (z. B. Passwort). Token ist das, was das System nach erfolgreicher Authentifizierung ausgibt, damit der Client seine Identität bei jeder Anfrage bestätigen kann, ohne das Passwort zu übermitteln. Das ist wie im Fitnessstudio: Sie zeigen einmal Ihre Ausweise an der Rezeption (Credentials), erhalten ein Armband (Token), und dann kommen Sie mit dem Armband hinein, ohne beim Drehkreuz mit dem Passport zu wedeln.

JWT fungiert normalerweise als ein solcher Token. Er überträgt die „minimal ausreichende“ Information über den Benutzer (und manchmal über seinen grundlegenden Zugriffskontext), damit der Server die Authentifizierung für die Dauer der konkreten Anfrage wiederherstellen kann.

Dabei ist es wichtig, sofort festzuhalten: JWT taucht nicht auf, weil wir eine modische Technologie wollen, sondern weil die stateless-Architektur erfordert, den Auth-Kontext zwischen Anfragen ohne serverseitige Session zu transportieren. JWT ist eines der Formate, das dies bequem macht, weil es kompakt, textbasiert, standardisiert und gut in HTTP integrierbar ist.

Aus Sicht unseres Projekts Secure Content Platform API bedeutet das eine einfache Sache: Wenn der Client beispielsweise auf /api/me oder /api/drafts/{id} zugreift, kann der Server den Benutzer nicht mehr über die Session „erinnern“. Er muss auf der Grundlage dessen, was Sie in der Anfrage mitbringen, wiederherstellen, wer Sie sind. JWT ist eine Möglichkeit, diesen Kontext mitzubringen.

3. Signierter Token: Integrität versus Geheimhaltung

Der schädlichste Irrtum über JWT lautet ungefähr so: „Wenn ich einen JWT habe, sind die Daten darin verborgen.“ Nein. JWT ist im typischen Szenario des Kurses signiert, nicht verschlüsselt. Und Signatur und Verschlüsselung lösen unterschiedliche Aufgaben.

Die Signatur beantwortet die Frage: „Konnte jemand die Daten im Token unbemerkt ändern?“. Es geht um Integrität. Wenn Sie einen Token erhalten, die Signatur prüfen und sie korrekt ist, können Sie darauf vertrauen, dass der Payload nach der Ausstellung nicht verändert wurde.

Aber die Signatur beantwortet nicht die Frage: „Kann jemand den Inhalt lesen?“. Bei einem normalen JWT ist der Payload sichtbar. Er kann dekodiert werden. Und das ist normal. JWT wurde als Format konzipiert, das bequem zu transportieren ist, nicht als Safe.

Daher ist es nützlich, JWT als einen durchsichtigen Behälter mit einem Siegel zu betrachten. Der Behälter ist durchsichtig – der Payload ist lesbar. Das Siegel ist vorhanden – Manipulation wird nach Prüfung der Signatur sichtbar. Daraus ergibt sich eine einfache technische Regel: In JWT dürfen keine sensiblen Daten abgelegt werden, weil jeder, der den Token in die Hände bekommt, sie sehen kann.

Und hier taucht ein weiterer erwachsener Gedanke auf: Die Sicherheit von JWT beruht nicht auf der „Geheimhaltung des Tokens“, sondern darauf, dass der Token nicht unbemerkt gefälscht werden kann, wenn die Signatur korrekt geprüft wird. Das ist eine grundlegend andere Denkweise als „verstecken wir die Daten einfach, dann wird es schon niemand merken“.

4. Base64URL: Lesbarkeit des Tokens

Am Anfang ärgert JWT dadurch, dass es wie eine chaotische Zeichenfolge aussieht. Tatsächlich sind die ersten beiden Teile des Tokens normales JSON, das nur in Base64URL verpackt ist, damit die Zeichenfolge bequem in HTTP und URL übertragen werden kann. Base64URL ist Kodierung, keine Tarnkappe.

Für diesen Punkt reicht eine Tatsache: Der Payload ist lesbar. Wenn dort E-Mail, Anzeigename oder etwas anderes Sensibles abgelegt wurde, ist es nicht „irgendwo im Backend geblieben“, sondern mit dem Token zum Client und in jede Zwischenschicht, in die der Token gelangt, mitgereist.

Das reicht bereits, um praktische Verpackung nicht mit echtem Schutz zu verwechseln.

5. JWT als Datenvertrag: Minimale Felder

JWT ist praktisch, weil es Daten tragen kann. JWT ist gefährlich, weil es zu viele Daten tragen kann. Ein Anfänger tappt meist in die Falle: „Da es ein Token ist, legen wir alles hinein, was wir brauchen könnten – damit wir später nicht zur Datenbank müssen.“ Das klingt nach Effizienz, wird aber meist zu Zerbrechlichkeit, Datenlecks und veralteten Realitäts-Snapshots.

Um sich im Zaum zu halten, ist es nützlich, JWT als Datenvertrag zu betrachten, nicht als „Sack, in den man alles stopfen kann“. Ein Vertrag bedeutet, dass Sie im Voraus entscheiden: Welche Felder werden wirklich benötigt, um den aktuellen Benutzer und den grundlegenden Zugriffskontext wiederherzustellen, und welche sind nur bequem, aber schädlich?

In unserem Projekt reduziert sich der minimale Vertrag normalerweise auf drei Dinge:

— Wer der Benutzer ist (sub und/oder stabile userId);
— Welchen kompakten Zugriffskontext er hat, z. B. Rollen;
— Bis zu welchem Zeitpunkt dieser Token gültig ist (exp).

Das reicht aus, um die Authentifizierung wiederherzustellen und eine grundlegende Zugriffsentscheidung zu treffen. Alles, was nicht bei jeder Anfrage sofort benötigt wird, wird normalerweise besser auf dem Server nachgelesen.

Genau so verwechselt man den Token nicht mit dem Benutzerprofil: JWT sollte das Minimum transportieren, ohne das eine stateless-Anfrage nicht bearbeitet werden kann, und nicht die gesamte Biografie, Einstellungen und sensible Felder.

6. JWT im Sicherheitsmodell: Allgemeiner Ablauf

Damit JWT nicht nur ein Format bleibt, sondern zu einem verständlichen Architekturstück wird, ist es hilfreich, das Gesamtbild einer Anfrage zu sehen. Hier genügt es, auf der Ebene „wer macht was“ zu bleiben, ohne Klassen und Filter. Dann ist die Rolle des Tokens selbst sichtbar, nicht nur die zukünftige Implementierung.

sequenceDiagram
    participant C as Client
    participant A as "API (Secure Content Platform)"

    C->>A: "(1) Login mit Anmeldedaten (Benutzername/Passwort)"
    A-->>C: "(2) Antwort: Access-Token (JWT)"
    C->>A: "(3) Anfrage an /api/me mit Token"
    A->>A: "(4) Überprüft Signatur und Gültigkeitsdauer des Tokens"
    A->>A: "(5) Extrahiert subject/roles und trifft Zugriffsentscheidung"
    A-->>C: "(6) JSON-Antwort oder Sicherheitsfehler (401/403)"

Auf dieser Ebene sind bereits mehrere Dinge sichtbar, die gut mit unserem bisherigen Wissen übereinstimmen.

Erstens: Token ist nicht dasselbe wie Credentials. Credentials werden zum Zeitpunkt 1 benötigt, der Token erscheint nach 2. Zweitens: JWT hilft genau im stateless-Teil zwischen den Anfragen 3: Der Server erhält jedes Mal keine Cookie-Session, sondern einen Token. Drittens: Der Payload ist immer lesbar, aber den darin enthaltenen Daten kann man nur nach Prüfung der Signatur und der Gültigkeitsdauer vertrauen.

Und schließlich: JWT hebt Ihre Geschäftsrestriktionen nicht auf. Wenn ein Benutzer die Rolle USER hat, wird daraus nicht „darf veröffentlichen“. Wenn ein Benutzer userId=42 hat, bedeutet das nicht, dass ein Entwurf mit authorId=99 plötzlich „seiner“ ist. Owner-basierte Regeln bleiben Owner-basierte Regeln, nur dass wir statt „ID aus der Session holen“ die „ID aus dem Token holen“ (oder aus der wiederhergestellten Authentifizierung, die auf Basis des Tokens aufgebaut wird).

Wenn Sie dieses Bild im Kopf behalten, wird es leichter sein, alle weiteren Details zu besprechen. Und umgekehrt: Wenn Sie anfangen, JWT als eine Reihe magischer Bibliotheksaufrufe zu lernen, landen Sie schnell in dem Zustand „irgendwie funktioniert es, aber ich weiß nicht, warum“.

7. Typische Fehler beim ersten Kennenlernen von JWT

In JWT gibt es auf Entwicklerebene kaum „komplexe Mathematik“, aber viele Fallstricke des mentalen Modells. Und das ist normal: Das Gehirn vereinfacht gern. Nur in der Sicherheit wirken Vereinfachungen manchmal wie der „Selbstzerstörungsknopf“ – nur ohne schöne Animation.

Fehler Nr. 1: Zu glauben, dass Base64URL den Payload „versteckt“.
Wenn Sie eine lange Zeichenfolge sehen, neigt die Hand dazu zu sagen: „Na, das ist kodiert, also versteckt.“ Base64URL ist nur eine Möglichkeit, JSON in eine sichere Zeichenfolge zu verpacken. Wenn Sie den Payload mit einer einzigen Codezeile dekodieren können, kann ihn jeder dekodieren, der den Token hat.

Fehler Nr. 2: „Signatur“ und „Verschlüsselung“ verwechseln.
Die Signatur macht Fälschung schwierig, aber das Lesen – einfach. Aus diesem Grund wird der Token oft mit einem „Siegel“ verglichen, und das ist eine passende Analogie. Wenn Sie zusätzliche Daten in den Payload stecken, hilft die Signatur nicht: Die zusätzlichen Daten sind für jeden sichtbar, der den Token sieht.

Fehler Nr. 3: Alles Mögliche „für die Zukunft“ in den Token packen.
JWT wird schnell zu einer Mini-Datenbank: Profil, Einstellungen, Biografie, Lieblingsfarbe der Schaltfläche „Speichern“. Dann beginnt es ein Eigenleben zu führen: Token blähen sich auf, Strukturen ändern sich, veraltete Felder tauchen auf, der Client trägt Megabyte in Headern herum. JWT gewinnt gerade durch Minimalismus: Je weniger Daten, desto einfacher die Wartung und desto geringer das Leckrisiko.

Fehler Nr. 4: Sensible Felder ablegen (selbst „keine richtigen Passwörter“).
passwortHash, interne Sicherheitsflags, Werte, die man nicht verlieren möchte oder die gefährlich anzuzeigen sind – all das sollte nicht im lesbaren Payload stehen. „Aber es ist doch ein Hash!“ – kein Argument. Es ist ein sensibler Wert, und Sie wollen ihn nicht in fremden Logs, in Proxys, in DevTools oder auf einem Screenshot sehen, den jemand an einen Ticket angehängt hat.

Fehler Nr. 5: Zu glauben, dass JWT automatisch die Autorisierung löst.
JWT ist ein Format. Es ersetzt nicht Ihre URL-Regeln und @PreAuthorize. Es führt keinen Ownership-Check für Sie durch. Wenn in Ihrem Projekt die Regel gilt „Nur der Autor kann den Entwurf bearbeiten“, bleibt es die Regel „Nur der Autor kann den Entwurf bearbeiten“, selbst wenn im Token das Wort USER in Großbuchstaben und in einer schönen Schriftart steht.

1
Aufgabe
Spring Security, Level 22, Lektion 0
Gesperrt
Dekodierung des Base64URL-Payloads
Dekodierung des Base64URL-Payloads
1
Aufgabe
Spring Security, Level 22, Lektion 0
Gesperrt
Überprüfung der Feldsammlung für JWT Payload
Überprüfung der Feldsammlung für JWT Payload
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION