web-dev-qa-db-de.com

RSA-Signierung für JWT

Ich implementiere ein Anmeldesystem mit Hilfe des JWT-Schemas (JsonWebToken). Nachdem ein Benutzer sich angemeldet hat, loggt der Server eine JWT ein und leitet sie an den Client weiter.

Der Client gibt dann das Token mit jeder Anforderung zurück und der Server überprüft das Token, bevor er eine Antwort zurücksendet.

Das ist so, wie man es erwarten würde, aber ich habe Probleme mit der Logik des Prozesses. Aus allen mathematischen Artikeln, die ich gelesen habe, scheint es, dass die RSA-Signatur asymmetrische Schlüssel zum Signieren verwendet. Da der öffentliche Schlüssel, wie der Name schon sagt, dem Client zugänglich gemacht wird und der private Schlüssel auf dem Server verbleibt, ist es sinnvoll, das JWT mit dem öffentlichen Schlüssel zu signieren, der an den Client gesendet wird, und dies auf der Serverseite mit zu bestätigen der private Schlüssel.

Bei jedem Beispiel und jeder Bibliothek, die ich sehe, scheint es jedoch andersherum zu sein, eine Idee, warum es so ist? Wenn eine JWT mit dem privaten Schlüssel signiert und mit dem öffentlichen Schlüssel verifiziert wird, als was ist der Punkt?

13
Liran Cohen

Zunächst einmal, entschuldige mich, diese Antwort wurde ziemlich lang.

Wenn Sie Ihre Token mit RSA verschlüsseln und ein verbindender Client ein Webbrowser ist, werden dem Client niemals die RSA-Schlüssel (öffentlich oder privat) angezeigt. Dies liegt daran, dass der Client vermutlich nicht die Gültigkeit der JWT überprüfen muss, nur der Server muss dies tun. Der Client hält nur an der JWT fest und zeigt sie dem Server, wenn Sie dazu aufgefordert werden. Dann prüft der Server, ob er gültig ist, wenn er das Token sieht.

Warum brauchen Sie also eine Kombination aus öffentlichem und privatem Schlüssel für JWTs? Zunächst einmal müssen Sie keinen öffentlichen/privaten Schlüsselalgorithmus verwenden.

Sie können JWTs mit einer Reihe verschiedener Algorithmen kodieren, darunter auch RSA. Andere beliebte Optionen zum Kodieren Ihrer JWTs sind ECDSA- oder HMAC-Algorithmen (der JWT-Standard unterstützt andere ebenfalls ). HMAC ist insbesondere kein öffentlicher/privater Schlüssel. Es gibt nur einen Schlüssel, den Schlüssel, der zum Verschlüsseln und Entschlüsseln der Token verwendet wird. Sie können sich den privaten Schlüssel sowohl zum Signieren als auch zum Entschlüsseln der JWTs vorstellen. Ich bin auf keinen Fall ein Experte, aber hier sind die Schlussfolgerungen, zu denen ich kürzlich meine eigenen Nachforschungen gezogen habe:

Die Verwendung von HMAC ist Nizza, da dies die schnellste Option ist. Um die JWTs zu entschlüsseln, müssen Sie jedoch jemandem den einen Schlüssel geben, der alles tut. Das Teilen dieses Schlüssels mit einem anderen bedeutet, dass diese Person nun auch sign -Marker und so tun kann, als wären Sie Sie. Wenn Sie mehrere Serveranwendungen erstellen, die alle Ihre JWTs überprüfen müssen, möchten Sie möglicherweise nicht, dass jede Anwendung auch Token codieren kann (verschiedene Programmierer verwalten möglicherweise die verschiedenen Anwendungen und teilen die Enzypting-Fähigkeit mit mehr Menschen sind ein Sicherheitsrisiko usw.). In diesem Fall ist es besser, einen streng kontrollierten privaten Schlüssel (und eine App, die das Signieren vornimmt) zur Verfügung zu haben, und dann den öffentlichen Schlüssel mit anderen Personen gemeinsam zu nutzen, damit sie die Token überprüfen können. Hier wird der private Schlüssel zum Verschlüsseln der Token und der öffentliche Schlüssel zum Entschlüsseln verwendet. In diesem Fall möchten Sie RSA oder ECDSA auswählen.

Als Beispiel könnten Sie über ein Ökosystem von Apps verfügen, mit denen alle eine Verbindung zu .__ herstellen. die gleiche Datenbank. Um Benutzer anzumelden, sendet jede App Benutzer an einen dedizierte, "Anmelden" -App. Diese App hat den privaten Schlüssel. Das andere Apps können überprüfen, ob die Person mit dem öffentlichen Schlüssel angemeldet ist (aber Sie können sich nicht anmelden).

Die Recherche, die ich durchgeführt habe, deutet darauf hin, dass RSA die beste Option für die meisten JWT-Apps in diesem Bereich ist. Dies liegt daran, dass Ihre App Token theoretisch häufig überprüft. RSA ist bei der Verifizierung viel schneller als ECDSA. ECDSA ist in erster Linie Nizza, weil die Schlüssel kleiner sind. Dies macht es für https-Zertifikate besser, da Sie den öffentlichen Schlüssel an den Browser des Clients senden müssen. In der JWT-Umgebung befinden sich die Schlüssel jedoch auf einem Server, so dass die Speichergröße n/a ist und die Überprüfungsgeschwindigkeit wichtiger ist.

Fazit: Wenn Sie eine kleine App ohne mehrere kleinere "Micro-Service-Apps" erstellen/wenn Sie der einzige Entwickler sind, wählen Sie wahrscheinlich HMAC zur Verschlüsselung Ihrer Schlüssel. Ansonsten wählen Sie wahrscheinlich RSA. Ich bin jedoch kein Experte, sondern nur jemand, der kürzlich dieses Thema gegoogelt hat, also nehmen Sie dies mit einem Körnchen Salz.

30
John

Ihr Vorschlag:

es ist sinnvoll, die JWT mit dem öffentlichen Schlüssel zu signieren, der an die .__ gesendet wird. Client und verifizieren Sie es serverseitig mit dem privaten Schlüssel.

das ist nicht richtig. Die Signatur erfolgt mit dem privaten Schlüssel des Servers, die Verschlüsselung erfolgt mit dem öffentlichen Schlüssel des Clients. So funktioniert PKI im Allgemeinen.

9
Hans Z.

Es besteht ein Unterschied zwischen dem Signieren/Überprüfen und dem Verschlüsseln/Entschlüsseln von Daten. Die Semantik kann jedoch ähnlich sein.

Sie signieren Daten mit einem privaten Schlüssel, über den nur kontrollierte Quellen verfügen, sodass jeder, der die Informationen erhält, Ihren öffentlichen Schlüssel verwenden kann, um zu bestätigen, dass diese Informationen tatsächlich von Ihnen gesendet wurden und dieselben Informationen sind, die Sie senden wollten.

Sie verschlüsseln Daten mit einem öffentlichen Schlüssel und entschlüsseln mit einem privaten Schlüssel. Das klingt im Gegenteil, folgt jedoch dem logischen Konzept des Signierens. Wenn Sie Daten zwischen Person A und Person B senden möchten, haben beide Personen ein öffentliches/privates Schlüsselpaar und teilen sich ihre öffentlichen Schlüssel, wenn sie sich treffen (Handshake). A erstellt eine Nachricht für B und verschlüsselt sie mit dem öffentlichen Schlüssel von B und sendet ihn an B. Nun kann niemand ohne Bs privaten Schlüssel diese Nachricht einschließlich A entschlüsseln, obwohl sie sie ursprünglich gesendet haben.

In Bezug auf JWT ist eine JWT-Nutzlast an sich nur Base64-codierter JSON mit einigen standardisierten Feldern. Die Signatur ermöglicht es jemandem mit dem öffentlichen Schlüssel, die Informationen zu überprüfen, die nicht von jemandem in der Mitte geändert wurden. Ähnlich wie eine Prüfsumme, jedoch mit zusätzlichen, auf Sicherheit beruhenden, warmen, unscharfen Gefühlen. Der Inhalt der signierten JWT ist für den Endbenutzer und alle, die sich in der Mitte befinden, leicht zu erkennen (base64 kodiert wie Unicode oder utf-8, keine Verschlüsselung), weshalb es generell verpönt ist, sensible Daten in einer JWT wie Passwörter oder PII .

Wie bereits erwähnt, enthalten die meisten JWTs Informationen, die nicht für Kunden bestimmt sind, sondern den staatenlosen Teil der RESTful-Dienste erleichtern sollen. Normalerweise enthält eine JWT eine Konto-ID, eine Benutzer-ID und häufig Berechtigungen als "Claims". Ein API-Endpunkt kann die Signatur überprüfen und darauf vertrauen, dass die Ansprüche vom Client nicht geändert werden. Wenn der Client die JWT für jede Anforderung sendet, muss der Endpunkt nicht mehr lange auf die Datenbank zugreifen, nur um zu ermitteln, wo er sich befindet, indem er einfach eine Signatur mit einem öffentlichen Schlüssel überprüft.

Außerdem können signierte JWTs verschlüsselt werden. Gemäß der JWE-Spezifikation wird die Payload nach dem Signieren verschlüsselt und dann vor der Überprüfung entschlüsselt. Der Kompromiss hier ist, dass alle Endpunkte auch über den privaten Schlüssel verfügen müssen, um die JWT zu entschlüsseln, aber Endbenutzer können den Inhalt der JWT nicht sehen. Ich sage Kompromisse, weil in der Regel private Schlüssel sicher gehalten werden sollen und ein weit verbreiteter privater Schlüssel weniger sicher ist. Sicherheit, Risikobewertung und Kosten/Nutzen von Verschlüsselung sind ein ganz anderes Tier :)

1
evillive