Token als Cookie: Wie schliesse ich die Sicherheitslücken?

RezaScript

Bekanntes Mitglied
Hallo,

ich benutze Spring Security mit JWT und frage mich wie sicher mein Vorgehen ist.

So gehe ich vor:
  1. Benutzer loggt sich im Browser ein
  2. Ein Request wird an Backend gesendet und es wird ein Token generiert
  3. Token wird an Browser gesendet
  4. Browser speichert das Token als Cookie
Somit ist der Benutzer angemeldet. Wenn er nun also eine geschützte Seite aufruft, sendet der Browser den Wert des Cookies als Bearer Token an Server. Der Server überprüft, ob das Token valid ist und gibt dann eine Rückmeldung.

Soweit alles gut. Meine Frage ist, was, wenn das Token von Angreifer geklaut wird? HttpOnly-Flag kann ich ja nicht setzen, da das Cookie als Bearer Token eingesetzt wird. Tokens haben zwar ein kurzes Verfallsdatum, aber in dieser Zeit ist das Account des Users immer noch angreifbar. Wie schliesse ich diese Lücke?
 

LimDul

Top Contributor
Welcher Angreifer? Wo exakt ist da dein Problem.

Technisch lässt sich das nicht vermeiden. Der Benutzer (=Browser) muss etwas an den Server schicken, was beweist "Ich bin der für den ich mich ausgebe". Dieses etwas muss der Benutzer (=Browser) natürlich kennen und speichern.
 

Oneixee5

Top Contributor
Cookies werden im HTTP-Header übertragen, genau wie andere Header-Attribute. Der HTTP-Header wird bei der Übertragung verschlüsselt wenn HTTPS verwendet wird. Vorausgesetzt die Verschlüsselung ist sicher - alles OK soweit. Um das Cookie zu stehlen müsste ein Angreifer direkten Zugang zu deinem Rechner haben oder eine Sicherheitslücke im Browser würde das Cookie für andere Webseiten sichtbar machen. Wenn ein Angreifer direkten Zugang zu deinem Rechner hat, könnte er auch die Inhalte der Übertragung unverschlüsselt mitschneiden. Er ist also gar nicht unbedingt auf das Cookie angewiesen.
 

RezaScript

Bekanntes Mitglied
Der Angreifer könnte z.B. ein Add-on sein, das der Benutzer in seinem Browser installiert hat. Oder im Worst-Case-Szenario, jemand fragt dich, ob er kurz dein Handy oder Laptop ausleihen darf und macht sich dann ein Foto vom Cookie. Wie auch immer, wer der Angreifer ist und wie er ans Cookie herankommt ist nicht wichtig. Fakt ist, der Angreifer besitzt das Cookie und meine Frage ist, wie ich damit umgehen kann.

Spontan kommt mir Zwei-Faktor-Authentifizierung in den Sinn, die aktiviert werden soll, wenn die IP des Clients anders ist als gewöhnlich. Mich interessiert, wie grosse Websites damit vorgehen.
 

KonradN

Super-Moderator
Mitarbeiter
Das Problem ist doch generell vorhanden. Du hast einen Bearer Token und den musst Du irgendwie speichern.

Ein Cookie kann dazu dienen, aber meines Wissens ist der in der Größe begrenzt, was problematisch werden kann, wenn im Token viele Claims sind.

Zwei-Faktor-Authentifizierung ist ja an einer anderen Stelle. Die Authentifizierung ist ja, was erfolgt, damit ein Token ausgestellt wird. Egal wie die auch immer ausfällt: Am Ende hast Du das Token.

Hier kommen maximal andere Technologien in Frage wie crsf und so. Dann ist das Token nur gültig mit dem dazugehörigen Session Token.

Du kannst aber auch darauf verzichten, das Token in einem Cookie zu speichern. Statt in einem Cookie kannst Du es auch einfach innerhalb Deiner Anwendung speichern. Dann gibt es kein Token mehr, das Du auslesen kannst. Aber wenn die Anwendung im Browser läuft, dann geht man in die Developer Console und schaut sich die Variablen an oder die Requests zum Backend, in denen dann ja ein Authorization Header mitgegeben wird.

Aber du hast keine Alternative. Dieses Token ist nur sehr begrenzt gültig. Bei Alternativen wie dem Authorization Basic Header hast Du ja die deutlich länger gültigen Daten, die nur encoded aber nicht verschlüsselt sind.
 

Oneixee5

Top Contributor
Der Angreifer könnte z.B. ein Add-on sein, das der Benutzer in seinem Browser installiert hat.
Ja das stimmt, ist aber ein typischer Fall von: selber Schuld! Jedem ist klar, Browser-Erweiterungen können verwendet werden, um die Surfaktivitäten eines Benutzers zu verfolgen und private Daten zu stehlen. Somit kannst du für dich entscheiden was wichtiger ist, Sicherheit und Privatsphäre oder Komfort und/oder was auch immer du mit der Browser-Erweiterung erreichen möchtest.
jemand fragt dich, ob er kurz dein Handy oder Laptop ausleihen darf und macht sich dann ein Foto vom Cookie.
Gleiches Prinzip: entweder man achtet auf Sicherheit oder man lässt sich übers Ohr hauen. Dann muss man sich eben von dem Dienst abmelden.
Technik kann nicht vor Fehlern der Nutzer schützen.
 

RezaScript

Bekanntes Mitglied
@KonradN, ich brauche aber das Cookie als "Remember me". Das Ablaufdatum des Tokens habe ich auf 7 Tage gestellt, damit der User sich nicht jeden Tag einloggen muss.

@Oneixee5, nehmen wir mal den Angreifer weg. Angenommen, der User hat auf der Website Mist gebaut und soll gesperrt werden. Wenn ich mit Sessions arbeiten würde, könnte ich relativ leicht die Session zerstören und somit ist der User mit dieser Session nicht mehr eingeloggt. Mein Problem ist folgendes: Ich speichere das Token in einem Cookie. Wenn ich das Cookie lösche, ist der User zwar aus Client-Sicht ausgeloggt, aber nicht aus Server-Sicht, denn das Token kann ich ja nicht löschen oder verändern. Es bleibt so lange valid, bis es abläuft.
 

LimDul

Top Contributor
Wenn du einen User sperrst, ist die Session egal. Der User wird als gesperrt markiert und ihm damit die Berechtigung entzogen - egal wie er sich meldet, in dem Augenblick, wo den User lädst, siehst du, dass er gesperrt ist und Ende.
 

KonradN

Super-Moderator
Mitarbeiter
@KonradN, ich brauche aber das Cookie als "Remember me". Das Ablaufdatum des Tokens habe ich auf 7 Tage gestellt, damit der User sich nicht jeden Tag einloggen muss.
Ja, aber dann ist es doch so wie gewollt. Daher ist die Frage, was Du hier genau willst.

Entweder Du speicherst es, dann hast Du das Risiko, dass es jeder, der es irgendwie lesen kann, nutzen kann. Das sieht mir nach einem "Wasch mich, aber mach mich nicht naß" Problem aus.

Angenommen, der User hat auf der Website Mist gebaut und soll gesperrt werden.
Das ist doch kein Problem. Das Token besagt doch nur: Es ist der User. Dieser User ist aber gesperrt, d.h. der Server weiss: Der User ist gesperrt.

Übertragen wir es einmal in unser Leben:
Das Token ist der Personalausweis. Den bekomme ich irgendwie. Und dem vertraust Du. Aber nur, weil ich Dir meinen Ausweis zeige und Du dann sicher weisst, wer ich bin, bedeutet das ja nicht, dass ich Zugriff habe.

Klar, Du kannst etwas haben wie: Jeder mit einem Ausweis hat das Recht zu etwas. Aber in der Regel hast Du weitergehende Rechte / Daten hinterlegt.

Wenn Du nun aber alles im Token speichern willst über claims, dann hast Du tatsächlich das Problem: Du sperrst den User, aber der User hat noch immer ein Token mit Claim, dass er Zugriff hat. Dann hättest Du tatsächlich dieses Problem. Hier gibt es zwei Ansätze:

a) Token Revocation: OAuth 2.0 Token Revocation - EIn Token wird widerrufen. Setzt aber voraus, dass das Token bekannt ist (sonst kannst Du es nicht revoken) und der Server muss nicht nur das Token auswerten sondern muss dann immer nachfragen, ob das Token noch gültig ist. Bringt also Sicherheit aber bringt einiges mehr an Aufwand.

b) Das Token gilt nur ganz kurz. Dann hat der User noch für paar Minuten die Rechte. Das Anmelden wird vermieden, weil es zwei Token gibt. Neben dem Access Token gibt es noch ein Refresh Token. Dann würde der Client regelmäßig mit dem Refresh Token ein neues Access Token anfordern und damit würden veränderte Claims mitgeteilt.
 

LimDul

Top Contributor
Vielleicht um noch mal etwas zu erläutern, was gerne mal nicht sauber getrennt wird.

Es gibt Authentifizierung und Berechtigungen. Das sind zwei komplett verschiedene Konzepte, die meist zusammen in einen Topf geworfen werden. Und aus dem Artikel kommt noch die Session hinzu.

Authentifzierung: Wer bin ich. Insbesondere im Context OAuth2 übernimmt dies der OAuth2 Provider (Keycloak, Google, ...)
Berechtigungen: Was darf der User. Setzt voraus, dass ich den User eindeutig identifiziert, also authentifiziert habe.
Sessions: HTTP ist ein Stateless Protokoll. Eine Webapplication hat aber oft einen State. Das heißt der Server braucht eine Möglichkeit bei einem Request zu wissen, das der zu einer Session gehört.

So, was der Artikel nur sagt: Speichere nicht deinen State (Also die Daten der Session) in einem JWT Token und speichere dieses Token dann im Client (egal ob als Cookie oder Local Storage). Denn dann hast du das Problem das Daten nun auf dem Client leben - was sie nie sollten - Cryptographie oder her.

Das JWT Token sollte nur dazu dienen, dass der OAuth2 Provider dem Server sagen kann "Der User ist XY". Da der OAuth2 Server nicht direkt mit der Webapplication reden kann (bzw. kann schon, aber er kann es nicht dem HTTP Request zuordnen, den der User schickt), schickt der OAuth2 Server das JWT Token an den Client und der wiederum an der Server. Da das Cryptographisch signiert ist, kann er nichts ändern.

Das einzige, was du nun nicht so einfach invalidieren kannst, ist die Existenz des Users im Authentifizierungssystem. Sprich, dass der User dort gelöscht wurde, stellst du erst bei einem Refresh fest. Aber das ist auch kein Problem, weil die Berechtigungsprüfung erfolgt in der Regel in deinem System.
 

KonradN

Super-Moderator
Mitarbeiter
Das JWT Token sollte nur dazu dienen, dass der OAuth2 Provider dem Server sagen kann "Der User ist XY". Da der OAuth2 Server nicht direkt mit der Webapplication reden kann (bzw. kann schon, aber er kann es nicht dem HTTP Request zuordnen, den der User schickt), schickt der OAuth2 Server das JWT Token an den Client und der wiederum an der Server. Da das Cryptographisch signiert ist, kann er nichts ändern.
Wobei ich es aus der Praxis durchaus kenne dass eben auch Berechtigungen weiter gegeben werden über Claims.

Es gibt dann halt einen Identity Provider eines Unternehmens und das Unternehmen hat entsprechende Prozesse um die User zu verwalten. Und diese Prozesse will ein Unternehmen natürlich nicht für jede Anwendung neu erfinden. Daher ist es sinnvoll, wenn man da dann einfach eine Berechtigungszuweisung im Provider machen kann um zu sagen: Der User darf auf eine Applikation zugreifen.

Also ganz wichtig: Das sind keine Low-Level Berechtigungen sondern wirklich nur ganz wenige, ganz grobe Rechte, wie
  • ist ein User der Anwendung
  • ist ein Admin der Anwendung
 

mihe7

Top Contributor
Wir mappen die identifizierten Akteure auf Rollen. Mit einer Rolle sind fixe Berechtigungen (Zugriff auf Use Cases) verbunden. Diese Rechte werden vom Container durchgesetzt. Ein User kann gegenüber der Anwendung mehrere Rollen einnehmen. Rollen können in Gruppen zusammengefasst werden. Benutzer sind wiederum Gruppen zugeordnet. Feingranularere Berechtigungen werden in der Anwendung definiert und von dieser auch durchgesetzt. Ich denke, das ist 0815-Standard.
 

Ähnliche Java Themen

Neue Themen


Oben