web-dev-qa-db-fra.com

Comprendre la signature RSA pour JWT

J'implémente un système de connexion à l'aide du système JWT (JsonWebToken). En gros, après la connexion/connexion d'un utilisateur, le serveur signe un JWT et le transmet au client.

Le client renvoie ensuite le jeton à chaque demande et le serveur vérifie le jeton avant de renvoyer une réponse.

C’est à peu près ce à quoi vous vous attendez, mais j’ai un problème avec la logique du processus. D'après tous les articles mathématiques que j'ai lus, il semble que la signature RSA utilise des clés asymétriques pour la signature. Comme la clé publique, comme son nom l'indique, est exposée au client et que la clé privée est conservée sur le serveur, il est logique de signer le JWT avec la clé publique qui est envoyée au client et de la vérifier côté serveur à l'aide de la clé privée.

Cependant, pour chaque exemple et chaque bibliothèque, je vois que cela semble être l'inverse, vous ne savez pas pourquoi? Si un JWT est signé avec la clé privée et vérifié avec le public, quel est le problème?

13
Liran Cohen

Tout d'abord, excusez-moi, cette réponse a été plutôt longue.

Si vous utilisez RSA pour chiffrer vos jetons et qu'un client se connectant est un navigateur Web, le client ne verra jamais les clés RSA (publiques ou privées). En effet, le client n'a vraisemblablement pas besoin de vérifier que le fichier JWT est valide, seul le serveur doit le faire. Le client ne fait que conserver le JWT et le montre au serveur lorsque cela lui est demandé. Ensuite, le serveur vérifie sa validité lorsqu’il voit le jeton.

Alors, pourquoi pourriez-vous avoir besoin d'un combo de clé publique/privée pour JWT? Tout d’abord, vous n’avez pas besoin d’utiliser un algorithme de clé publique/privée.

Vous pouvez coder les JWT avec un certain nombre d'algorithmes différents, RSA étant l'un d'entre eux. D'autres choix populaires pour coder vos fichiers JWT sont les algorithmes ECDSA ou HMAC (le standard JWT prend en charge les autres également ). HMAC, en particulier, n'est pas un schéma de clé publique/privée. Il n'y a qu'une clé, la clé, qui sert à chiffrer et à déchiffrer les jetons. Vous pouvez penser à cela en utilisant la clé privée pour signer et déchiffrer les fichiers JWT. Je ne suis en aucun cas un expert en la matière, mais voici les conclusions auxquelles je suis parvenue lors de mes propres recherches:

Utiliser HMAC, c'est bien parce que c'est l'option la plus rapide. Cependant, pour décrypter les fichiers JWT, vous devez donner à quelqu'un la clé qui fait tout. Partager cette clé avec quelqu'un d'autre signifie que cette personne peut désormais aussi signer des jetons et faire semblant d'être vous-même. Si vous créez plusieurs applications serveur devant toutes pouvoir vérifier vos JWT, vous ne voudrez peut-être pas que toutes les applications aient la possibilité d'encoder des jetons également (différents programmeurs peuvent gérer les différentes applications, en partageant la capacité d'encryptage avec plus de ressources). personnes est un risque de sécurité, etc.). Dans ce cas, il est préférable d’avoir une clé privée étroitement contrôlée (et une application qui effectue la signature), puis de partager la clé publique avec d’autres personnes pour leur permettre de vérifier les jetons. Ici, la clé privée est utilisée pour chiffrer les jetons et la clé publique pour les déchiffrer. Dans ce cas, vous voudriez choisir RSA ou ECDSA.

Par exemple, vous pouvez avoir un écosystème d'applications auxquelles toutes les applications se connectent la même base de données. Pour connecter les utilisateurs, chaque application envoie des personnes à un, dédié, "se connecter" app. Cette application a la clé privée. L'autre les applications peuvent vérifier que la personne est connectée à l'aide de la clé publique (mais elles ne peuvent pas se connecter).

Les recherches que j'ai effectuées montrent que RSA est la meilleure option pour la plupart des applications JWT de ce scénario. En effet, en théorie, votre application vérifiera fréquemment les jetons. RSA est beaucoup plus rapide que ECDSA lors de la vérification. ECDSA est avant tout agréable car les touches sont de taille réduite. Cela le rend meilleur pour les certificats https car vous devez envoyer la clé publique au navigateur du client. Dans le scénario JWT, les clés restent sur un serveur. La taille de stockage est donc n/a et la vitesse de vérification est plus importante.

Conclusion: si vous construisez une petite application sans plusieurs «applications de micro-services» plus petites/vous êtes le seul développeur, choisissez probablement HMAC pour chiffrer vos clés. Sinon, choisissez probablement RSA. Encore une fois cependant, je ne suis pas un expert, mais juste une personne qui a récemment fait des recherches sur Google sur ce sujet.

30
John

Votre suggestion:

il est logique de signer le JWT avec la clé publique qui est envoyée au client et vérifiez-le côté serveur en utilisant la clé privée.

n'est pas correcte. La signature se fait avec la clé privée du serveur, le chiffrement avec la clé publique du client. C’est ainsi que fonctionne l’ICP en général.

9
Hans Z.

Il existe une différence entre la signature/vérification et le cryptage/décryptage des données, mais la sémantique peut être similaire.

Vous signez les données avec une clé privée dont seules les sources contrôlées disposent, de sorte que toute personne qui reçoit l'information peut utiliser votre clé publique pour valider que cette information a bien été envoyée par vous et correspond à la même information que vous aviez l'intention de transmettre.

Vous chiffrez les données avec une clé publique et déchiffrez avec une clé privée. Cela semble opposé, mais découle en réalité du même concept logique que la signature. Si vous souhaitez envoyer des données entre une personne A et une personne B, les deux personnes disposent d'une paire de clés publique/privée et partagent leurs clés publiques lorsqu'elles se rencontrent (poignée de main). A construit un message pour B et le chiffre en utilisant la clé publique de B et l'envoie à B. Désormais, personne sans la clé privée de B ne peut décrypter ce message, y compris A, même s'il l'a envoyé à l'origine.

En termes de JWT, une charge JWT en elle-même n'est qu'un JSON codé en Base64 avec des champs normalisés. La signature permet à une personne disposant de la clé publique de valider les informations qui n'ont pas été modifiées par quelqu'un au milieu. Semblable à une somme de contrôle mais avec une sécurité supplémentaire basée sur des sentiments flous chaleureux. Le contenu de la JWT signée est facilement visible (l'utilisateur est au centre de la liste et l'utilisateur au centre est codé comme unicode ou utf-8, l'encodage étant comme l'unicode ou l'utf-8). PII .

Comme d'autres l'ont mentionné, la plupart des JWT contiennent des informations non destinées aux clients mais destinées à faciliter la partie sans état des services RESTful. Généralement, un JWT contient un identifiant de compte, un identifiant d'utilisateur et souvent des autorisations en tant que "revendications". Un point de terminaison API peut vérifier la signature et faire en sorte que les revendications ne soient pas modifiées par le client. Le fait que le client envoie le JWT pour chaque demande évite au point de terminaison de faire beaucoup de bases de données dans les deux sens, simplement pour vérifier où elles se trouvent en vérifiant simplement une signature avec une clé publique.

En outre, les fichiers JWT signés peuvent être chiffrés. Selon la spécification JWE , le contenu est chiffré après la signature, puis déchiffré avant la vérification. En contrepartie, tous les ordinateurs d'extrémité doivent également disposer de la clé privée pour déchiffrer le JWT, mais les utilisateurs finaux ne pourront pas voir le contenu du JWT. Je dis bien, car les clés privées sont généralement sécurisées et une clé privée largement distribuée est moins sécurisée. La sécurité, l’évaluation des risques et le rapport coût/bénéfice du cryptage est une toute autre bête :)

1
evillive