it-swarm.com.de

Bewährte Methoden für die serverseitige Verarbeitung von JWT-Token

(aus diesem Thread hervorgegangen, da dies wirklich eine eigene Frage ist und nicht spezifisch für NodeJS usw.)

Ich implementiere einen REST API-Server mit Authentifizierung, und ich habe die JWT-Token-Behandlung erfolgreich implementiert, damit sich ein Benutzer über einen/login-Endpunkt mit Benutzername/Kennwort anmelden kann, auf dem sich ein JWT-Token befindet Das Token wird in jeder authentifizierten API-Anforderung vom Client an den Server übergeben, auf dessen Grundlage das Servergeheimnis zum Überprüfen des Tokens verwendet wird.

Ich versuche jedoch, die Best Practices genau zu verstehen, wie und in welchem ​​Umfang das Token validiert werden sollte, um ein wirklich sicheres System zu erstellen. Was genau sollte bei der "Validierung" des Tokens beachtet werden? Reicht es aus, dass die Signatur mithilfe des Servergeheimnisses überprüft werden kann, oder sollte ich auch das Token und/oder die Token-Nutzdaten mit einigen auf dem Server gespeicherten Daten abgleichen?

Ein tokenbasiertes Authentifizierungssystem ist nur dann so sicher wie die Übergabe von Benutzername/Passwort bei jeder Anfrage, wenn es mindestens genauso schwierig ist, einen Token zu erhalten wie ein Passwort eines Benutzers. In den Beispielen, die ich gesehen habe, sind die einzigen Informationen, die zum Erstellen eines Tokens erforderlich sind, der Benutzername und das serverseitige Geheimnis. Bedeutet dies nicht, dass ein böswilliger Benutzer, der für eine Minute Kenntnis vom Servergeheimnis erlangt, Token für jeden Benutzer erstellen kann? Dadurch haben Sie nicht nur Zugriff auf einen bestimmten Benutzer, wie es der Fall wäre, wenn ein Passwort erhalten würde, sondern tatsächlich auf alle Benutzerkonten?

Das bringt mich zu den Fragen:

1) Sollte sich die JWT-Token-Validierung darauf beschränken, die Signatur des Tokens selbst zu überprüfen, wobei nur die Integrität des Servergeheimnisses zu berücksichtigen ist, oder von einem separaten Validierungsmechanismus begleitet werden?

  • In einigen Fällen habe ich die kombinierte Verwendung von Tokens und Serversitzungen gesehen, bei denen nach erfolgreicher Anmeldung über den/login-Endpunkt eine Sitzung aufgebaut wird. API-Anforderungen validieren das Token und vergleichen auch die im Token gefundenen decodierten Daten mit einigen in der Sitzung gespeicherten Daten. Das Verwenden von Sitzungen bedeutet jedoch das Verwenden von Cookies. In gewisser Weise wird der Zweck eines tokenbasierten Ansatzes außer Kraft gesetzt. Es kann auch Probleme für bestimmte Clients verursachen.

  • Man kann sich vorstellen, dass der Server alle derzeit verwendeten Token in einem Memcache oder ähnlichem aufbewahrt, um sicherzustellen, dass selbst bei einer Gefährdung des Servergeheimnisses ein Angreifer möglicherweise "gültige" Token erzeugt, nur die genauen Token, die über den Endpunkt/login generiert wurden würde akzeptiert werden. Ist das vernünftig oder nur überflüssig?

2) Wenn die Überprüfung der JWT-Signatur das einzige Mittel zur Validierung von Token ist, dh die Integrität des Servergeheimnisses ist die Bruchstelle, wie sollten Servergeheimnisse verwaltet werden? Aus einer Umgebungsvariablen lesen und einmal pro bereitgestelltem Stack erstellen (randomisiert?)? Regelmäßig neu erstellt oder gedreht (und wenn ja, wie vorhandene gültige Token behandelt werden, die vor dem Drehen erstellt wurden, aber nach dem Drehen überprüft werden müssen, reicht es möglicherweise aus, wenn der Server zu einem bestimmten Zeitpunkt das aktuelle und das vorherige Geheimnis beibehält) ? Etwas anderes?

Vielleicht bin ich einfach zu paranoid, wenn es darum geht, dass das Servergeheimnis kompromittiert wird. Dies ist natürlich ein allgemeineres Problem, das in allen kryptografischen Situationen angegangen werden muss ...

102
JHH

Ich habe auch für meine Bewerbung mit Token gespielt. Obwohl ich in keiner Weise ein Experte bin, kann ich einige meiner Erfahrungen und Gedanken zu diesem Thema mitteilen.

Der Punkt von JWTs ist im Wesentlichen Integrität. Es stellt einen Mechanismus für Ihren Server bereit, mit dem überprüft werden kann, ob das bereitgestellte Token echt ist und von Ihrem Server bereitgestellt wurde. Dafür sorgt die Signatur, die über Ihr Geheimnis generiert wird. Ja, wenn Ihr Geheimnis irgendwie durchgesickert ist, kann diese Person Tokens generieren, die Ihr Server für ihre eigenen hält. Ein tokenbasiertes System wäre aufgrund der Signaturüberprüfung immer noch sicherer als Ihr Benutzername/Passwort-System. Und in diesem Fall hat Ihr System andere Sicherheitsprobleme, wenn jemand Ihr Geheimnis hat, als jemand, der gefälschte Token herstellt (und selbst dann stellt das bloße Ändern des Geheimnisses sicher, dass alle mit dem alten Geheimnis erstellten Token ungültig sind).

In Bezug auf die Nutzlast gibt die Signatur nur an, dass das bereitgestellte Token genau so war, wie es von Ihrem Server gesendet wurde. Es liegt natürlich an Ihnen, zu überprüfen, ob der Inhalt der Nutzdaten gültig oder für Ihre Anwendung geeignet ist.

Für Ihre Fragen:

1.) Nach meiner begrenzten Erfahrung ist es definitiv besser, Ihre Token mit einem zweiten System zu überprüfen. Das einfache Validieren der Signatur bedeutet lediglich, dass der Token mit Ihrem Geheimnis generiert wurde. Das Speichern von erstellten Token in einer Art Datenbank (Redis, Memcache/SQL/Mongo oder einem anderen Speicher) ist eine fantastische Methode, um sicherzustellen, dass Sie nur Token akzeptieren, die Ihr Server erstellt hat. In diesem Szenario spielt es keine große Rolle, wenn Ihr Geheimnis durchgesickert ist, da generierte Token ohnehin nicht gültig sind. Dies ist der Ansatz, den ich mit meinem System verfolge: Alle generierten Token werden in einer Datenbank gespeichert (redis). Bei jeder Anforderung überprüfe ich, ob sich das Token in meiner Datenbank befindet, bevor ich es akzeptiere. Auf diese Weise können Token aus beliebigen Gründen widerrufen werden, z. B. Token, die auf irgendeine Weise freigegeben wurden, Benutzerabmeldung, Kennwortänderungen, geheime Änderungen usw.

2.) Dies ist etwas, in dem ich nicht viel Erfahrung habe und das ich noch aktiv recherchiere, da ich kein Sicherheitsprofi bin. Wenn Sie Ressourcen finden, können Sie diese hier posten! Momentan verwende ich nur einen privaten Schlüssel, den ich von der Festplatte lade, aber das ist offensichtlich nicht die beste oder sicherste Lösung.

51
Akshay Dhalwala

Beachten Sie beim Implementieren von JWTs in Ihrer Anwendung die folgenden Punkte:

  • Halten Sie Ihre JWT-Lebensdauer relativ kurz und lassen Sie die Lebensdauer auf dem Server verwalten. Wenn Sie dies nicht tun und später weitere Informationen in Ihren JWTs benötigen, müssen Sie entweder 2 Versionen unterstützen oder warten, bis Ihre älteren JWTs abgelaufen sind, bevor Sie Ihre Änderung implementieren können. Sie können es einfach auf dem Server verwalten, wenn Sie nur das Feld iat im JWT betrachten und das Feld exp ignorieren.

  • Erwägen Sie, die URL der Anfrage in Ihr JWT aufzunehmen. Wenn Sie beispielsweise möchten, dass Ihr JWT am Endpunkt /my/test/path Verwendet wird, fügen Sie ein Feld wie 'url':'/my/test/path' In Ihr JWT ein, um sicherzustellen, dass es nur auf diesem Pfad verwendet wird. Wenn Sie dies nicht tun, stellen Sie möglicherweise fest, dass Benutzer Ihre JWTs an anderen Endpunkten verwenden, auch an solchen, für die sie nicht erstellt wurden. Sie können stattdessen auch eine md5 (url) einfügen, da eine große URL in der JWT die JWT sehr viel größer macht und sie ziemlich groß werden kann.

  • Der JWT-Ablauf sollte für jeden Anwendungsfall konfigurierbar sein, wenn JWTs in einer API implementiert werden. Wenn Sie beispielsweise 10 Endpunkte für 10 verschiedene Anwendungsfälle für JWTs haben, müssen Sie sicherstellen, dass jeder Endpunkt JWTs akzeptiert, die zu unterschiedlichen Zeiten ablaufen. Auf diese Weise können Sie einige Endpunkte stärker als andere sperren, wenn beispielsweise die von einem Endpunkt bereitgestellten Daten sehr vertraulich sind.

  • Anstatt JWTs nach einer bestimmten Zeit einfach ablaufen zu lassen, sollten Sie JWTs implementieren, die beide unterstützen:

    • N-Verwendungen - können nur N-mal verwendet werden, bevor sie ablaufen und
    • verfallen nach einer bestimmten Zeitspanne (wenn Sie nur ein Token verwenden, möchten Sie nicht, dass es für immer lebt, wenn es nicht verwendet wird, oder?)
  • Alle JWT-Authentifizierungsfehler sollten einen "Fehler" -Antwortheader generieren, der angibt, warum die JWT-Authentifizierung fehlgeschlagen ist. z.B. "abgelaufen", "keine Verwendungen mehr", "widerrufen" usw. Dadurch wissen Implementierer, warum ihre JWT fehlschlägt.

  • Ziehen Sie in Betracht, den "Header" Ihrer JWTs zu ignorieren, da diese Informationen verlieren, und Hackern ein gewisses Maß an Kontrolle zu geben. Dies betrifft hauptsächlich das Feld alg im Header - ignorieren Sie dies und nehmen Sie an, dass der Header das ist, was Sie unterstützen möchten, da dies Hacker vermeidet, die versuchen, den Algorithmus None zu verwenden, der den entfernt Signatur-Sicherheitsüberprüfung.

  • JWTs sollten einen Bezeichner enthalten, aus dem hervorgeht, von welcher App das Token generiert wurde. Wenn Ihre JWT beispielsweise von zwei verschiedenen Clients erstellt werden, mychat und myclassifiedsapp, sollte jeder den Projektnamen oder etwas Ähnliches im Feld "iss" in der JWT enthalten, z. "iss": "mychat"

  • JWTs sollten nicht in Protokolldateien protokolliert werden. Der Inhalt einer JWT kann protokolliert werden, nicht jedoch die JWT selbst. Dadurch wird sichergestellt, dass Entwickler oder andere Benutzer keine JWTs aus Protokolldateien abrufen und andere Benutzerkonten bearbeiten können.
  • Stellen Sie sicher, dass Ihre JWT-Implementierung den Algorithmus "None" nicht zulässt, damit Hacker keine Token erstellen, ohne sie zu signieren. Diese Fehlerklasse kann vollständig vermieden werden, indem der "Header" Ihres JWT ignoriert wird.
  • Erwägen Sie nachdrücklich, iat (ausgestellt am) anstelle von exp (Ablaufdatum) in Ihren JWTs zu verwenden. Warum? Da iat im Grunde bedeutet, wann die JWT erstellt wurde, können Sie dies auf dem Server anpassen, wenn die JWT abläuft, basierend auf dem Erstellungsdatum. Wenn jemand in einem exp passiert, der 20 Jahre in der Zukunft liegt, lebt die JWT im Grunde genommen für immer! Beachten Sie, dass Sie JWTs automatisch ablaufen lassen, wenn ihr iat in der Zukunft liegt, aber ein wenig Spielraum einräumen (z. B. 10 Sekunden), falls die Client-Zeit nicht mit der Server-Zeit synchron ist.
  • Erwägen Sie, einen Endpunkt zum Erstellen von JWTs aus einer JSON-Nutzlast zu implementieren, und zwingen Sie alle implementierenden Clients, diesen Endpunkt zum Erstellen ihrer JWTs zu verwenden. Dies stellt sicher, dass Sie alle gewünschten Sicherheitsprobleme lösen können, wenn Sie JWTs an einem Ort erstellen. Wir haben dies in unserer App nicht sofort getan und müssen jetzt langsam die Sicherheitsupdates auf der Serverseite von JWT herausfiltern, da unsere fünf verschiedenen Clients Zeit für die Implementierung benötigen. Stellen Sie außerdem sicher, dass Ihr Erstellungsendpunkt eine Reihe von JSON-Nutzdaten akzeptiert, die von JWTs erstellt werden sollen. Auf diese Weise wird die Anzahl der an diesem Endpunkt eingehenden HTTP-Anforderungen für Ihre Clients verringert.
  • Wenn Ihre JWTs an Endpunkten verwendet werden, die auch die Verwendung durch Sitzungen unterstützen, stellen Sie sicher, dass Sie nichts in Ihre JWT einfügen, was zur Erfüllung der Anforderung erforderlich ist. Sie können dies problemlos tun, wenn Sie sicherstellen, dass Ihr Endpunkt mit einer Sitzung funktioniert, wenn kein JWT bereitgestellt wird.
  • JWTs enthalten also im Allgemeinen eine Benutzer-ID oder eine Gruppen-ID und ermöglichen basierend auf diesen Informationen den Zugriff auf einen Teil Ihres Systems. Stellen Sie sicher, dass Sie nicht zulassen, dass Benutzer in einem Bereich Ihrer App die Identität anderer Benutzer annehmen, insbesondere wenn dies den Zugriff auf vertrauliche Daten ermöglicht. Warum? Nun, selbst wenn Ihr JWT-Generierungsprozess nur für "interne" Dienste zugänglich ist, könnten Entwickler oder andere interne Teams JWTs generieren, um auf Daten für einen beliebigen Benutzer zuzugreifen, z. der CEO eines zufälligen Kundenunternehmens. Wenn Ihre App beispielsweise Kunden Zugriff auf Finanzunterlagen bietet, kann ein Entwickler durch Generieren einer JWT die Finanzunterlagen aller Unternehmen abrufen! Und wenn ein Hacker trotzdem in Ihr internes Netzwerk eindringt, kann er dasselbe tun.
  • Wenn Sie zulassen möchten, dass eine URL, die eine JWT enthält, in irgendeiner Weise zwischengespeichert wird, stellen Sie sicher, dass die Berechtigungen für verschiedene Benutzer in der URL und nicht in der JWT enthalten sind. Warum? Da Benutzer möglicherweise Daten abrufen, sollten sie dies nicht tun. Angenommen, ein Superuser meldet sich bei Ihrer App an und fordert die folgende URL an: /mysite/userInfo?jwt=XXX, Und diese URL wird zwischengespeichert. Sie melden sich ab und einige Minuten später meldet sich ein regulärer Benutzer bei Ihrer App an. Sie erhalten den zwischengespeicherten Inhalt - mit Informationen über einen Superuser! Dies geschieht in der Regel weniger auf dem Client und mehr auf dem Server, insbesondere in Fällen, in denen Sie einen CDN wie Akamai verwenden und einige Dateien länger leben lassen. Dies kann behoben werden, indem die entsprechenden Benutzerinformationen in die URL eingefügt und auf dem Server überprüft werden, auch für zwischengespeicherte Anforderungen, z. B. /mysite/userInfo?id=52&jwt=XXX.
  • Wenn Ihr JWT wie ein Sitzungscookie verwendet werden soll und nur auf demselben Computer funktionieren soll, für den das JWT erstellt wurde, sollten Sie in Betracht ziehen, Ihrem JWT das Feld jti hinzuzufügen. Dies ist im Grunde ein CSRF-Token, mit dem sichergestellt wird, dass Ihre JWT nicht vom Browser eines Benutzers an einen anderen Benutzer weitergegeben werden kann.
38
Brad Parks

Ich glaube nicht, dass ich ein Experte bin, aber ich möchte einige Gedanken über Jwt teilen.

  • 1: Wie Akshay sagte, ist es besser, ein zweites System zur Validierung Ihres Tokens zu haben.

    a .: So gehe ich damit um: Ich speichere den erzeugten Hash mit der Ablaufzeit in einem Sitzungsspeicher. Um ein Token zu validieren, muss es vom Server ausgestellt worden sein.

    b.:Es gibt mindestens eine Sache, die überprüft werden muss, welche Signaturmethode verwendet wird. z.B :

    header :
    {
      "alg": "none",
      "typ": "JWT"
    }
    

Einige Bibliotheken, die JWT validieren, würden diese akzeptieren, ohne den Hash zu überprüfen. Das bedeutet, dass sich ein Hacker Rechte einräumen kann, ohne zu wissen, mit welchem ​​Salz Sie den Token signiert haben. Stellen Sie immer sicher, dass dies nicht passieren kann. https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/

c .: Die Verwendung eines Cookies mit einer Sitzungs-ID ist für die Validierung Ihres Tokens nicht hilfreich. Wenn jemand die Sitzung eines Lambda-Benutzers entführen möchte, muss er lediglich einen Schnüffler verwenden (z. B. Wireshark). Dieser Hacker würde beide Informationen gleichzeitig haben.

  • 2: Es ist für jedes Geheimnis dasselbe. Es gibt immer einen Weg, es zu wissen.

Die Art und Weise, wie ich damit umgehe, ist mit dem Punkt 1.a. : Ich habe ein Geheimnis mit einer Zufallsvariablen gemischt. Das Geheimnis ist für jeden Token einzigartig.

Ich versuche jedoch, die Best Practices genau zu verstehen, wie und in welchem ​​Umfang das Token validiert werden sollte, um ein wirklich sicheres System zu erstellen.

Wenn Sie die bestmögliche Sicherheit wünschen, sollten Sie nicht blind Best Practices befolgen. Der beste Weg ist zu verstehen, was Sie tun (ich denke, es ist in Ordnung, wenn ich Ihre Frage sehe) und dann die Sicherheit zu bewerten, die Sie benötigen. Und wenn der Mossad Zugriff auf Ihre vertraulichen Daten haben möchte, wird er immer einen Weg finden. (Mir gefällt dieser Blog-Beitrag: https://www.schneier.com/blog/archives/2015/08/mickens_on_secu.html )

Viele gute Antworten hier. Ich werde einige der Antworten integrieren, die meiner Meinung nach am relevantesten sind, und weitere Vorschläge hinzufügen.

1) Sollte sich die JWT-Token-Validierung darauf beschränken, die Signatur des Tokens selbst zu überprüfen, wobei nur die Integrität des Servergeheimnisses zu berücksichtigen ist, oder von einem separaten Validierungsmechanismus begleitet werden?

Nein, aus Gründen, die nichts mit der Kompromittierung eines Token-Geheimnisses zu tun haben. Bei jeder Anmeldung eines Benutzers über einen Benutzernamen und ein Kennwort sollte der Autorisierungsserver entweder das generierte Token oder Metadaten zu dem generierten Token speichern. Stellen Sie sich diese Metadaten als Berechtigungssatz vor. Ein bestimmtes Benutzer- und Anwendungspaar sollte jeweils nur ein gültiges Token oder eine gültige Berechtigung haben. Nützliche Metadaten sind die dem Zugriffstoken zugeordnete Benutzer-ID, die App-ID und der Zeitpunkt, zu dem das Zugriffstoken ausgestellt wurde (wodurch vorhandene Zugriffstoken gesperrt und ein neues Zugriffstoken ausgestellt werden kann). Überprüfen Sie bei jeder API-Anforderung, ob das Token die richtigen Metadaten enthält. Sie müssen die Informationen darüber, wann die einzelnen Zugriffstoken ausgestellt wurden, beibehalten, damit ein Benutzer vorhandene Zugriffstoken widerrufen kann, wenn seine Kontoanmeldeinformationen gefährdet sind. Melden Sie sich erneut an und beginnen Sie mit der Verwendung eines neuen Zugriffstokens. Dadurch wird die Datenbank mit der Zeit aktualisiert, zu der das Zugriffstoken ausgestellt wurde (die Autorisierungszeit, die erstellt wurde). Überprüfen Sie bei jeder API-Anforderung, ob die Ausgabezeit des Zugriffstokens nach der erstellten Autorisierungszeit liegt.

Andere Sicherheitsmaßnahmen umfassten das Nichtprotokollieren von JWTs und das Erfordernis eines sicheren Signaturalgorithmus wie SHA256.

2) Wenn die Überprüfung der JWT-Signatur das einzige Mittel zur Validierung von Token ist, dh die Integrität des Servergeheimnisses ist die Bruchstelle, wie sollten Servergeheimnisse verwaltet werden?

Die Gefährdung durch Servergeheimnisse würde es einem Angreifer ermöglichen, Zugriffstoken für jeden Benutzer auszustellen, und das Speichern von Zugriffstoken-Daten in Schritt 1 würde den Server nicht notwendigerweise daran hindern, diese Zugriffstoken zu akzeptieren. Angenommen, einem Benutzer wurde ein Zugriffstoken ausgestellt, und später generiert ein Angreifer ein Zugriffstoken für diesen Benutzer. Die Autorisierungszeit des Zugriffstokens wäre gültig.

Wie Akshay Dhalwala sagt, haben Sie größere Probleme, wenn Ihr serverseitiges Geheimnis kompromittiert ist, da dies bedeutet, dass ein Angreifer Ihr internes Netzwerk, Ihr Quellcode-Repository oder beides kompromittiert hat.

Ein System, das den Schaden eines kompromittierten Servergeheimnisses mindert und das Speichern von Geheimnissen im Quellcode vermeidet, umfasst die Token-Secret-Rotation mithilfe eines Koordinierungsdienstes wie https://zookeeper.Apache.org . Verwenden Sie einen Cron-Job, um etwa alle paar Stunden ein App-Geheimnis zu generieren (wie lange Ihre Zugriffstoken auch gültig sind), und senden Sie das aktualisierte Geheimnis an Zookeeper. Konfigurieren Sie auf jedem Anwendungsserver, der das Token-Geheimnis kennen muss, einen ZK-Client, der bei jeder Änderung des ZK-Knotenwerts aktualisiert wird. Speichern Sie ein primäres und ein sekundäres Geheimnis. Setzen Sie bei jeder Änderung des Token-Geheimnisses das neue Token-Geheimnis auf das primäre und das alte Token-Geheimnis auf das sekundäre. Auf diese Weise sind vorhandene gültige Token weiterhin gültig, da sie gegen das sekundäre Geheimnis validiert werden. Wenn das sekundäre Geheimnis durch das alte primäre Geheimnis ersetzt wird, sind alle mit dem sekundären Geheimnis ausgegebenen Zugriffstoken sowieso ungültig.

3
skeller88

IETF haben einen RFC in Bearbeitung in der Arbeitsgruppe oAuth= siehe: https://tools.ietf.org/id/draft-ietf-oauth-jwt-bcp-05. html

0
SPoint