Si vous pouvez décoder JWT, comment sont-ils sécurisés?

302

Si j'obtiens un JWT et que je peux décoder la charge utile, comment est-ce sécurisé? Ne pourrais-je pas simplement récupérer le jeton dans l'en-tête, décoder et modifier les informations utilisateur dans la charge utile, et les renvoyer avec le même secret codé correct?

Je sais qu'ils doivent être sécurisés, mais j'aimerais vraiment comprendre les technologies. Qu'est-ce que je rate?

PixMach
la source
2
md5('original messaged' + secret) != md5('changed message' + secret)donc si quelqu'un change le message, vous pouvez le détecter
Pithikos
vrai pour un cas idéal, cependant, md5 a des collisions. @Pithikos
Yash Kumar Verma
@YashKumarVerma oui, c'est juste pour en montrer l'essentiel puisque tout le monde connaît md5.
Pithikos
1
@ user1955934, il est codé en base64, NON crypté. Vous pouvez simplement le décoder avec n'importe quel décodeur base64.
Pithikos
1
donc le client devra envoyer à la fois le hachage et le jeton jwt? et plus tard du côté serveur, ils essaieront de hacher le jeton jwt en utilisant secret et de comparer avec le hachage?
user1955934

Réponses:

387

Les JWT peuvent être signés, chiffrés ou les deux. Si un jeton est signé, mais non chiffré, tout le monde peut lire son contenu, mais lorsque vous ne connaissez pas la clé privée, vous ne pouvez pas la modifier. Sinon, le destinataire remarquera que la signature ne correspondra plus.

Réponse à votre commentaire: je ne suis pas sûr de bien comprendre votre commentaire. Juste pour être sûr: connaissez-vous et comprenez-vous les signatures numériques? Je vais juste expliquer brièvement une variante (HMAC, qui est symétrique, mais il y en a beaucoup d'autres).

Supposons qu'Alice veuille envoyer un JWT à Bob. Ils connaissent tous les deux un secret partagé. Mallory ne connaît pas ce secret, mais veut interférer et changer le JWT. Pour éviter cela, Alice calcule Hash(payload + secret)et ajoute cela comme signature.

Lors de la réception du message, Bob peut également calculer Hash(payload + secret)pour vérifier si la signature correspond. Si toutefois Mallory change quelque chose dans le contenu, elle n'est pas en mesure de calculer la signature correspondante (ce qui serait le cas Hash(newContent + secret)). Elle ne connaît pas le secret et n'a aucun moyen de le découvrir. Cela signifie que si elle change quelque chose, la signature ne correspondra plus et Bob n'acceptera tout simplement plus le JWT.

Supposons que j'envoie le message à une autre personne {"id":1}et que je le signe Hash(content + secret). (+ est juste une concaténation ici). J'utilise la fonction de hachage SHA256, et la signature que je reçois est: 330e7b0775561c6e95797d4dd306a150046e239986f0a1373230fda0235bda8c. Maintenant, c'est votre tour: jouez le rôle de Mallory et essayez de signer le message {"id":2}. Vous ne pouvez pas parce que vous ne savez pas quel secret j'ai utilisé. Si je suppose que le destinataire connaît le secret, il PEUT calculer la signature de n'importe quel message et vérifier s'il est correct.

Misch
la source
8
Donc, la signature est modifiée lorsque la charge utile est modifiée? J'avais l'impression que le jeton était au format [en-tête]. [Charge utile]. [Signature] la signature est-elle calculée en combinant la charge utile et le secret? Si c'était le cas, une charge utile avec un identifiant différent ne serait-elle pas la même pour ce secret? Comme si les données étaient {id: 1} et utilisées pour calculer la partie signature du jeton avec le secret, cela ne signifierait-il pas que {id: 2} serait valide pour l'utilisateur 2, et donc l'utilisateur 1 pourrait changer id à 2 et le jeton serait le même?
PixMach
7
Je vous ai donné un exemple pour rendre les choses encore plus claires, mais je ne vous expliquerai pas tout le concept des signatures numériques et des HMAC. Veuillez lire ces choses, il y a beaucoup de documents qui l'expliquent.
Misch
11
Ah je comprends maintenant. Je ne sais pas pourquoi je manquais l'idée que le hachage secret ne serait pas correct lorsque vous modifiez la charge utile, car le hachage secret devrait être recalculé. Pour une raison quelconque, je pensais toujours qu'il était indépendant. Ce dernier morceau m'a vraiment permis de rentrer chez moi. Merci de m'avoir accompagné.
PixMach
30
J'ai une question connexe. Qu'est-ce qui empêche quelqu'un d'usurper l'identité d'Alice avec le JWT copié?
Morrowless
25
Si quelqu'un a le JWT, il peut se faire passer pour Alice. Vous devez donc faire attention à la façon dont vous l'enregistrez et l'envoyez. Vous devez également définir une expiration pour cela dans la charge utile. De cette façon, si quelqu'un vole le JWT, il dispose d'un délai limité pour l'utiliser. Jetez un œil à stormpath.com/blog/…
Geraint Anderson
134

Vous pouvez aller sur jwt.io, coller votre jeton et lire le contenu. C'est choquant pour beaucoup de gens au départ.

La réponse courte est que JWT ne se préoccupe pas du cryptage. Il se soucie de la validation. C'est-à-dire, il peut toujours obtenir la réponse pour "manipuler le contenu de ce jeton"? Cela signifie que la manipulation par l'utilisateur du jeton JWT est futile car le serveur connaîtra et ignorera le jeton. Le serveur ajoute une signature basée sur la charge utile lors de l'émission d'un jeton au client. Plus tard, il vérifie la charge utile et la signature correspondante.

La question logique est quelle est la motivation pour ne pas se préoccuper des contenus cryptés?

  1. La raison la plus simple est parce qu'il suppose que c'est un problème résolu pour la plupart. Si vous traitez avec un client comme le navigateur Web par exemple, vous pouvez stocker les jetons JWT dans un cookie qui est secure(n'est pas transmis via HTTP, uniquement via HTTPS) et httpOnly(ne peut pas être lu par Javascript) et parle au serveur via un canal crypté (HTTPS). Une fois que vous savez que vous disposez d'un canal sécurisé entre le serveur et le client, vous pouvez échanger en toute sécurité JWT ou tout ce que vous voulez.

  2. Cela permet de garder les choses simples. Une implémentation simple facilite l'adoption, mais elle permet également à chaque couche de faire ce qu'elle fait le mieux (laissez HTTPS gérer le chiffrement).

  3. JWT n'est pas destiné à stocker des données sensibles. Une fois que le serveur reçoit le jeton JWT et le valide, il est libre de rechercher l'ID utilisateur dans sa propre base de données pour des informations supplémentaires pour cet utilisateur (comme les autorisations, l'adresse postale, etc.). Cela maintient JWT de petite taille et évite les fuites d'informations par inadvertance car tout le monde sait ne pas conserver les données sensibles dans JWT.

Ce n'est pas trop différent de la façon dont les cookies eux-mêmes fonctionnent. Les cookies contiennent souvent des charges utiles non chiffrées. Si vous utilisez HTTPS, tout va bien. Si vous ne l'êtes pas, il est conseillé de chiffrer les cookies sensibles eux-mêmes. Ne pas le faire signifiera qu'une attaque de l'homme du milieu est possible - un serveur proxy ou un FAI lit les cookies puis les rejoue plus tard en se faisant passer pour vous. Pour des raisons similaires, JWT doit toujours être échangé sur une couche sécurisée comme HTTPS.

aleemb
la source
4
Réfléchis-y! JWT devrait toujours être échangé sur une couche sécurisée comme HTTPS
codemirror
Mais si JWT n'est sécurisé que via HTTPS, pourquoi ne pas simplement envoyer la charge utile? POST -> nom d'utilisateur, mot de passe. Il est toujours chiffré non?
GeekPeek
@GeekPeek pour cela, vous devriez lire les bases de JWT, mais Session Auth comme vous le mentionnez est souvent tout ce dont vous avez besoin. JWT offre d'autres avantages mais fait des compromis webskeleton.com/webdev/2019/10/22/…
aleemb
17

Le contenu d'un jeton Web json (JWT) n'est pas intrinsèquement sécurisé, mais il existe une fonction intégrée pour vérifier l'authenticité du jeton. Un JWT est composé de trois hachages séparés par des points. Le troisième est la signature. Dans un système à clé publique / privée, l'émetteur signe la signature du jeton avec une clé privée qui ne peut être vérifiée que par sa clé publique correspondante.

Il est important de comprendre la distinction entre émetteur et vérificateur. Le destinataire du jeton est responsable de sa vérification.

L'utilisation sécurisée de JWT dans une application Web comporte deux étapes essentielles: 1) les envoyer sur un canal crypté et 2) vérifier la signature dès sa réception. La nature asymétrique de la cryptographie à clé publique rend possible la vérification de signature JWT. Une clé publique vérifie qu'un JWT a été signé par sa clé privée correspondante. Aucune autre combinaison de clés ne peut effectuer cette vérification, empêchant ainsi les tentatives d'emprunt d'identité. Suivez ces deux étapes et nous pouvons garantir avec certitude mathématique l'authenticité d'un JWT.

Plus de lecture: Comment une clé publique vérifie-t-elle une signature?

ThisClark
la source
2

Discutons du tout début:

JWT est une approche très moderne, simple et sécurisée qui s'étend aux jetons Web Json. Les jetons Web Json sont une solution sans état pour l'authentification. Il n'est donc pas nécessaire de stocker un état de session sur le serveur, ce qui est bien sûr parfait pour les API reposantes. Les API reposantes doivent toujours être sans état, et l'alternative la plus largement utilisée à l'authentification avec les JWT est de simplement stocker l'état de connexion de l'utilisateur sur le serveur à l'aide de sessions. Mais alors, bien sûr, ne suit pas le principe qui dit que les API reposantes doivent être sans état et c'est pourquoi des solutions comme JWT sont devenues populaires et efficaces.

Alors maintenant, savons comment l'authentification fonctionne réellement avec les jetons Web Json. En supposant que nous avons déjà un utilisateur enregistré dans notre base de données. Ainsi, le client de l'utilisateur commence par faire une demande de publication avec le nom d'utilisateur et le mot de passe, l'application vérifie ensuite si l'utilisateur existe et si le mot de passe est correct, puis l'application générera un jeton Web Json unique pour cet utilisateur uniquement.

Le jeton est créé en utilisant une chaîne secrète qui est stockée sur un serveur . Ensuite, le serveur renvoie ensuite ce JWT au client qui le stockera dans un cookie ou dans un stockage local. entrez la description de l'image ici

Tout comme cela, l'utilisateur est authentifié et essentiellement connecté à notre application sans laisser aucun état sur le serveur.

Donc, le serveur ne sait pas en fait quel utilisateur est réellement connecté, mais bien sûr, l'utilisateur sait qu'il est connecté parce qu'il a un jeton Web Json valide qui est un peu comme un passeport pour accéder aux parties protégées de l'application.

Encore une fois, juste pour vous assurer que vous avez eu l'idée. Un utilisateur est connecté dès qu'il récupère son jeton Web Json valide unique qui n'est enregistré nulle part sur le serveur. Et donc ce processus est donc complètement apatride.

Ensuite, chaque fois qu'un utilisateur souhaite accéder à un itinéraire protégé comme ses données de profil utilisateur, par exemple. Il envoie son Json Web Token avec une demande, c'est donc un peu comme montrer son passeport pour avoir accès à cet itinéraire.

Une fois que la demande arrive sur le serveur, notre application vérifie alors si le jeton Web Json est réellement valide et si l'utilisateur est vraiment ce qu'il dit être, eh bien, les données demandées seront envoyées au client et sinon, il y aura être une erreur indiquant à l'utilisateur qu'il n'est pas autorisé à accéder à cette ressource. entrez la description de l'image ici

Toute cette communication doit se faire via https, donc sécurisé et crypté Http afin d'empêcher que quiconque puisse avoir accès aux mots de passe ou aux jetons Web Json. Alors seulement, nous avons un système vraiment sécurisé.

entrez la description de l'image ici

Donc, un jeton Web Json ressemble à la partie gauche de cette capture d'écran qui a été prise du débogueur JWT à jwt.io Donc, c'est essentiellement une chaîne de codage composée de trois parties. L'en-tête, la charge utile et la signature Maintenant, l'en-tête n'est que quelques métadonnées sur le jeton lui-même et la charge utile est les données que nous pouvons encoder dans le jeton, toutes les données que nous voulons vraiment. Donc, plus nous voulons coder de données ici, plus le JWT est grand. Quoi qu'il en soit, ces deux parties ne sont que du texte brut qui sera encodé, mais pas crypté.

Donc, n'importe qui pourra les décoder et les lire , nous ne pouvons pas stocker de données sensibles ici. Mais ce n'est pas du tout un problème car dans la troisième partie, donc dans la signature, c'est là que les choses deviennent vraiment intéressantes. La signature est créée à l'aide de l'en-tête, de la charge utile et du secret enregistré sur le serveur.

Et tout ce processus est alors appelé signature du jeton Web Json . L'algorithme de signature prend l'en-tête, la charge utile et le secret pour créer une signature unique. Donc, seules ces données et le secret peuvent créer cette signature, d'accord? Ensuite, avec l'en-tête et la charge utile, ces signatures forment le JWT, qui est ensuite envoyé au client. entrez la description de l'image ici

Une fois que le serveur reçoit un JWT pour accorder l'accès à une route protégée, il doit le vérifier afin de déterminer si l'utilisateur est vraiment qui il prétend être. En d'autres termes, il vérifiera si personne n'a modifié l'en-tête et les données de charge utile du jeton. Encore une fois, cette étape de vérification vérifiera si aucun tiers n'a réellement modifié l'en-tête ou la charge utile du jeton Web Json.

Alors, comment fonctionne cette vérification? Eh bien, c'est en fait assez simple. Une fois le JWT reçu, la vérification prendra son en-tête et sa charge utile, et avec le secret qui est toujours enregistré sur le serveur, créera essentiellement une signature de test.

Mais la signature d'origine qui a été générée lors de la création du JWT est toujours dans le jeton, non? Et c'est la clé de cette vérification. Parce que maintenant, tout ce que nous avons à faire est de comparer la signature de test avec la signature d'origine. Et si la signature de test est la même que la signature d'origine, cela signifie que la charge utile et l'en-tête n'ont pas été modifiés. entrez la description de l'image ici

Parce que s'ils avaient été modifiés, la signature de test devrait être différente. Par conséquent, dans ce cas où il n'y a pas eu de modification des données, nous pouvons alors authentifier l'utilisateur. Et bien sûr, si les deux signatures sont réellement différentes, eh bien, cela signifie que quelqu'un a falsifié les données. Habituellement, en essayant de modifier la charge utile. Mais ce tiers manipulant la charge utile n'a bien sûr pas accès au secret, il ne peut donc pas signer le JWT. La signature d'origine ne correspondra donc jamais aux données manipulées. Et par conséquent, la vérification échouera toujours dans ce cas. Et c'est la clé pour faire fonctionner l'ensemble de ce système. C'est la magie qui rend JWT si simple, mais aussi extrêmement puissant.

Seigneur
la source
1

Seule la clé privée de JWT, qui se trouve sur votre serveur, déchiffrera le JWT chiffré. Ceux qui connaissent la privateKey pourront décrypter le JWT crypté.

Cachez la clé privée dans un emplacement sécurisé sur votre serveur et ne communiquez jamais la clé privée à quiconque.

sdfdsf sdf
la source
1
Les JWT ne sont pas toujours cryptés. Ils peuvent être signés, chiffrés, signés puis chiffrés ou chiffrés puis signés.
csauve
0

Pour les personnes qui ne peuvent pas se permettre des requêtes de base de données coûteuses comme moi, une option pour conserver les données sensibles (privilèges utilisateur, etc.) est, lors de la génération du JWT, vous pouvez crypter ces données et les attacher au jeton JWT. (Gardez la clé de cryptage dans le backend)

Lorsque vous souhaitez lire les informations sensibles, vous pouvez envoyer le jeton JWT au backend et le déchiffrer et récupérer les informations. De cette façon, vous n'avez pas à effectuer de recherches de base de données ou à avoir les informations sensibles nues dans le frontend via un jeton JWT

Nirojan Selvanathan
la source
-1

Je suggère de jeter un œil à JWE en utilisant des algorithmes spéciaux qui ne sont pas présents dans jwt.io pour décrypter

Lien de référence: https://www.npmjs.com/package/node-webtokens

jwt.generate('PBES2-HS512+A256KW', 'A256GCM', payload, pwd, (error, token) => {
  jwt.parse(token).verify(pwd, (error, parsedToken) => {
    // other statements
  });
});

Cette réponse est peut-être trop tardive ou vous avez peut-être déjà découvert le chemin, mais je pense tout de même qu'elle serait utile pour vous et pour les autres.

Un exemple simple que j'ai créé: https://github.com/hansiemithun/jwe-example

Mithun Shreevatsa
la source