Authentification angular jwt
Cet article est la première partie d’un guide étape par étape en deux parties pour l’implémentation de l’authentification basée sur JWT dans une application Angular (également applicable aux applications d’entreprise).
L’objectif de cet article est de commencer par apprendre en détail comment fonctionnent les jetons Web JSON (ou JWT), y compris comment ils peuvent être utilisés pour l’authentification des utilisateurs et la gestion de session dans une application Web.
Dans la partie 2, nous verrons ensuite comment l’authentification basée sur JWT peut être implémentée dans le contexte spécifique d’une application Angular, mais cet article ne concerne que les JWT .
Pourquoi une plongée profonde JWT ?
Avoir une vue d’ensemble détaillée des JWT est essentiel pour :
- mettre en œuvre une solution d’authentification basée sur JWT
- toutes sortes de dépannages pratiques : comprendre les messages d’erreur, les traces
- de pile choisir les tiers Conception
- d’une solution d’authentification interne
- Choix et configuration d’un service d’authentification tiers
Même lors du choix d’une solution d’authentification prête à l’emploi basée sur JWT, il y aura toujours un certain codage impliqué, en particulier sur le client, mais aussi sur le serveur.
À la fin de cet article, vous connaîtrez en profondeur les JWT, y compris une bonne compréhension des primitives cryptographiques sur lesquelles ils sont basés, qui sont utilisées dans de nombreux autres cas d’utilisation de la sécurité.
Vous saurez quand utiliser les JWT et pourquoi, vous comprendrez le format JWT au point de pouvoir dépanner manuellement les signatures, et vous connaîtrez plusieurs outils en ligne / Node pour le faire.
À l’aide de ces outils, vous serez en mesure de vous résoudre de nombreuses situations d’erreur liées à JWT. Alors, sans plus tarder, commençons par notre Plongée en profondeur JWT !
Pourquoi les JWT ?
Le plus grand avantage des JWT (par rapport à la gestion de session utilisateur à l’aide d’un jeton aléatoire en mémoire) est qu’ils permettent de déléguer la logique d’authentification à un serveur tiers qui peut être :
- un serveur d’authentification interne centralisé et développé sur mesure
- , plus généralement, un produit commercial tel qu’un LDAP capable d’émettre des
- JWT ou même un fournisseur d’authentification tiers entièrement externe, comme par exemple Auth0
Le serveur d’authentification externe peut être complètement séparé de notre serveur d’applications et n’a pas à partager de clé secrète avec d’autres éléments du réseau, à savoir avec notre serveur d’applications - il n’y a pas de clé secrète installée sur notre serveur qui pourrait être perdue ou volée accidentellement.
De plus, il n’est pas nécessaire d’établir une liaison directe en direct entre le serveur d’authentification ou le serveur d’applications pour que l’authentification fonctionne (nous y reviendrons plus tard).
De plus, le serveur d’applications peut être complètement sans état , car il n’est pas nécessaire de conserver des jetons en mémoire entre les demandes. Le serveur d’authentification peut émettre le jeton, le renvoyer puis le jeter immédiatement !
De plus, il n’est pas non plus nécessaire de stocker les résumés de mots de passe au niveau de la base de données de l’application, ce qui réduit le nombre de choses à voler et moins de bogues liés à la sécurité.
À ce stade, vous vous demandez peut-être : j’ai une application interne interne, les JWT sont-ils une bonne solution pour cela aussi ? Oui, dans la dernière section de cet article, nous aborderons l’utilisation des JWT dans un scénario d’entreprise typique de pré-authentification.
Table des matières
Dans cet article, nous allons aborder les sujets suivants :
- Qu’est-ce qu’un JWT ?
- Outils en ligne pour la validation JWT
- Quel est le format d’un jeton Web JSON
- JWT en bref : en-tête, charge utile, signature
- Base64Url (vs Base64)
- Gestion des sessions utilisateur avec JWT : objet et expiration
- La signature JWT HS256 - Comment ça marche ?
- Signatures numériques
- Fonctions de hachage et SHA-256
- La signature RS256 JWT - parlons de la crypto à clé publique
- Signatures RS256 vs HS256 - Laquelle est la meilleure ?
- Points de terminaison JWKS (JSON Web Key Set)
- Comment mettre en œuvre les JWT Signature Periodic Key Rotation JWT
- dans l’entreprise
- Résumé et conclusions Qu’est-ce qu’un
JWT ?
Un jeton Web JSON (ou JWT) est simplement une charge utile JSON contenant une revendication particulière. Le La propriété clé des JWT est que pour confirmer s’ils sont valides, il suffit de regarder le jeton lui-même.
Nous n’avons pas besoin de contacter un service tiers ou de garder les JWT en mémoire entre les demandes pour confirmer que la revendication qu’ils portent est valide - c’est parce qu’ils portent un code d’authentification de message ou MAC (nous y reviendrons plus tard).
Un JWT est composé de 3 parties : l’en-tête, la charge utile et la signature. Passons en revue chacun d’entre eux, en commençant par la charge utile.
À quoi ressemble une charge utile JWT ?
Voici un exemple d’objet de charge utile valide :
Dans ce cas, la charge utile contient des informations d’identification sur un utilisateur donné, mais en général, la charge utile peut être n’importe quoi d’autre, comme par exemple des informations sur un virement bancaire.
Il n’y a aucune restriction sur le contenu de la charge utile, mais il est important de savoir qu’un JWT n’est pas chiffré . Ainsi, toutes les informations que nous mettons dans le jeton sont toujours lisibles par toute personne qui intercepte le jeton.
Par conséquent, il est important de ne pas mettre dans la charge utile des informations utilisateur qu’un attaquant pourrait exploiter directement.
Le contenu de la charge utile est ensuite validé par le récepteur en inspectant la signature. Mais il existe plusieurs types de signatures, donc l’une des choses que le destinataire doit savoir est par exemple quel type de signature rechercher.
Cet objet JSON distinct est connu sous le nom d’en-tête JWT, et voici un exemple d’en-tête valide :
Dans cet en-tête, nous pouvons voir que le type de signature utilisé pour ce JWT était RS256.
Plus d’informations sur les multiples types de signatures dans un instant, concentrons-nous maintenant sur la compréhension de ce que la présence de la signature permet en termes d’authentification.
Signatures JWT - Comment sont-elles utilisées pour l’authentification ?
La dernière partie d’un JWT est la signature, qui est un code d’authentification de message (ou MAC). La signature d’un JWT ne peut être produite que par une personne en possession à la fois de la charge utile (plus l’en-tête) et d’une clé secrète donnée.
Voici comment la signature est utilisée pour garantir
- l’authentification : l’utilisateur soumet le nom d’utilisateur et le mot de passe à un serveur d’authentification, qui peut être notre serveur d’applications, mais il s’agit généralement d’un serveur distinct
- . Le serveur d’authentification valide la combinaison nom d’utilisateur et mot de passe et crée un jeton JWT avec une charge utile contenant l’identificateur technique de l’utilisateur et un horodatage
- d’expiration le serveur d’authentification prend ensuite une clé secrète et l’utilise pour signer l’en-tête plus la charge utile et la renvoie au navigateur de l’utilisateur (nous aborderons plus tard les détails exacts du fonctionnement de la signature)
- le navigateur prend le JWT signé et commence à l’envoyer à chaque requête HTTP à notre serveur d’applications
- Le JWT signé agit effectivement comme un identifiant d’utilisateur temporaire, qui remplace l’identifiant permanent qui est la combinaison de nom d’utilisateur et de mot de passe
Et à partir de là, voici ce que notre serveur d’applications fait avec le jeton JWT :
- notre serveur d’applications vérifie la signature JWT et confirme qu’en effet, quelqu’un en possession de la clé secrète a signé cette charge utile particulière
- La charge utile identifie un utilisateur particulier via un identifiant technique
- Seul le serveur d’authentification est en possession de la clé privée, et le serveur d’authentification ne donne des jetons qu’aux utilisateurs qui soumettent le mot de passe
- correct par conséquent, notre serveur d’applications peut être sûr que ce jeton a bien été donné à cet utilisateur particulier par le serveur d’authentification, ce qui signifie qu’il s’agit bien de l’utilisateur car il
avait le bon mot de passe - Le serveur procède au traitement de la requête HTTP en supposant qu’elle appartient bien à cet utilisateur
La seule façon pour un attaquant de se faire passer pour un utilisateur serait soit de voler à la fois son nom d’utilisateur et son mot de passe de connexion personnel, soit de voler la clé de signature secrète du serveur d’authentification.
Comme nous pouvons le voir, la signature est vraiment l’élément clé du JWT !
La signature est ce qui permet à un serveur entièrement sans état d’être sûr qu’une requête HTTP donnée appartient à un utilisateur donné, simplement en regardant un jeton JWT présent dans la requête elle-même, et sans forcer l’envoi du mot de passe à chaque fois avec la requête.
L’objectif des JWT est-il de rendre un serveur sans état ?
Rendre le serveur sans état est un effet secondaire agréable, mais le principal avantage des JWT est que le serveur d’authentification qui a émis le JWT et le serveur d’applications qui valide le JWT peuvent être deux serveurs complètement distincts.
Cela signifie qu’il n’y a besoin que d’une logique d’authentification minimale au niveau du serveur d’applications - nous n’avons besoin de vérifier le JWT !
Il serait possible pour un cluster complet d’applications de déléguer la connexion/inscription à un seul serveur d’authentification.
Cela signifie que les serveurs d’applications sont plus simples et plus sûrs, car une grande partie de la fonctionnalité d’authentification est concentrée sur le serveur d’authentification et réutilisée dans toutes les applications.
Maintenant que nous savons à un niveau général comment les JWT permettent l’authentification tierce sans état, entrons dans les détails de leur implémentation.
À quoi ressemble un jeton Web JSON ?
Pour en savoir plus sur les 3 éléments de construction JWT, voici une vidéo qui montre du code et un outil de validation JWT en ligne :
Jetons donc un coup d’œil à un exemple de JWT, tiré de l’outil de validation JWT en ligne disponible sur jwt.io :
Vous vous demandez peut-être, où sont passés les objets JSON ?? Nous les récupérerons dans un instant. En fait, à la fin de cet article, vous comprendrez en profondeur tous les aspects de cette corde à l’apparence étrange.
Jetons-y un coup d’œil : nous pouvons voir qu’il a 3 parties séparées par des points. La première partie avant le premier point est l’en-tête JWT :
La deuxième partie, entre le premier point et le second, est la charge utile :
Et la dernière partie, après le deuxième point, est la signature :
Si vous souhaitez confirmer que les informations sont bien présentes, copiez simplement la chaîne JWT complète ci-dessus sur l’outil officiel de validation JWT en ligne disponible chez jwt.io.
Mais alors, quels sont tous ces caractères, comment pouvons-nous relire les informations dans un JWT pour le dépannage ? Comment récupère-t-jwt.io les objets JSON ?
Base64 en bref, ou est-ce Base64Url ?
Croyez-le ou non, la charge utile, l’en-tête et la signature sont toujours là sous une forme lisible.
C’est juste que nous voulons nous assurer que lorsque nous envoyons le JWT sur le réseau, nous ne rencontrerons aucun de ces vilains problèmes d’encodage de caractères (« texte brouillé »).
Ce problème se produit parce que différents ordinateurs à travers le monde gèrent des chaînes dans différents encodages de caractères, tels que par exemple UTF-8, ISO 8859-1, etc.
Et ces problèmes sont omniprésents autant que les chaînes de caractères : chaque fois que nous avons une chaîne de caractères sur n’importe quelle plate-forme, nous avons un encodage utilisé. Même si nous n’avons pas spécifié d’encodage :
- soit le l’encodage du système d’exploitation sera utilisé
- ou il sera pris à partir d’un paramètre de configuration dans notre serveur
Nous voulons pouvoir envoyer des chaînes sur le réseau sans avoir à nous soucier de ces problèmes, nous choisissons donc un sous-ensemble de caractères que tous les encodages courants gèrent de la même manière, et c’est ainsi qu’est né le format d’encodage Base64.
Base64 vs Base64Url
Mais ce que nous voyons dans un JWT n’est en fait pas de la Base64 : c’est plutôt de la Base64Url .
C’est comme en Base64, mais il y a quelques caractères différents pour que nous puissions facilement envoyer un JWT dans le cadre d’un paramètre Url, ce qui est exactement ce qui se passe si, par exemple, nous utilisons une page de connexion tierce qui redirige ensuite vers notre site.
Donc, si nous prenons la deuxième partie de ce JWT (entre le premier et le deuxième point), nous obtenons la charge utile qui ressemble à ceci :
Exécutons-le simplement via un décodeur en ligne, comme par exemple celui-ci :
Nous récupérons une charge utile JSON ! C’est bon à savoir pour le dépannage. Nous avons cependant utilisé un décodeur Base64, nous y reviendrons plus tard, résumons maintenant ce que nous avons jusqu’à présent :
Ce format n’est vraiment qu’un moyen pratique d’envoyer du JSON sur un réseau.
Cette vidéo montre du code sur la façon de créer et de valider un JWT, et couvre en détail les parties En-tête et Charge utile :
Avant de passer à la signature, parlons de ce que nous devons mettre dans la charge utile dans le cas d’utilisation concret de l’authentification de l’utilisateur.
Gestion des sessions utilisateur avec les JWT : objet et expiration
Comme nous l’avons mentionné, un La charge utile JWT pourrait en principe être n’importe quelle réclamation, et pas seulement des informations d’identification de l’utilisateur. Mais l’utilisation de JWT pour l’authentification est un cas d’utilisation si courant qu’il existe quelques propriétés spécifiques d’une charge utile définies pour la prise en charge :
- Expiration de la session
- d’identification de l’utilisateur
Voici une charge utile avec quelques-unes des propriétés de charge utile JWT les plus couramment utilisées :
Voici ce que signifient ces propriétés standard :
- signifie l’entité émettrice, dans ce cas, notre serveur d’authentification
- est l’horodatage de création du JWT (en secondes depuis Epoch)
- contient l’identifiant technique de l’utilisateur
- contient l’horodatage d’expiration du jeton
C’est ce qu’on appelle un jeton porteur, et signifie implicitement :
Le serveur d’authentification confirme que le porteur de ce token est l’utilisateur avec l’ID suivant défini par la propriété : donnons l’accès à cet utilisateur
Maintenant que nous avons une bonne compréhension de la façon dont la charge utile est utilisée dans le cas typique de l’authentification de l’utilisateur, concentrons-nous maintenant sur la compréhension de la signature.
Il existe de nombreux types de signatures pour les JWT, dans cet article, nous allons en couvrir deux : HS256 et RS256. Commençons donc par le premier type de signature : HS256.
La signature numérique HS256 JWT - Comment ça marche ?
Comme la plupart des signatures, la signature numérique HS256 est basée sur un type de fonction particulier : une fonction de hachage cryptographique.
Cela peut sembler intimidant, mais c’est un concept qui vaut la peine d’être appris : ces connaissances étaient utiles il y a 20 ans et le seront pendant très longtemps. Une grande partie de la mise en œuvre pratique de la sécurité tourne autour des hachages, ils sont partout dans la sécurité des applications Web.
La bonne nouvelle, c’est qu’il est possible d’expliquer tout ce que nous devons savoir (en tant que développeurs d’applications Web) sur le hachage en quelques paragraphes, et c’est ce que nous allons faire ici.
Nous allons le faire en deux étapes : tout d’abord, nous allons parler de ce qu’est une fonction de hachage, puis nous verrons comment une telle fonction avec un mot de passe peut être combinée pour produire un code d’authentification de message (qui est la signature numérique).
À la fin de cette section, vous allez pouvoir reproduire vous-même la signature JWT HS256 à l’aide d’outils de dépannage en ligne et d’un package npm.
Qu’est-ce qu’une fonction de hachage ?
Une fonction de hachage est un type spécial de fonction avec des propriétés très uniques : elle a beaucoup de cas d’utilisation pratiques et utiles comme les signatures numériques.
Nous allons parler de 4 propriétés intéressantes de ces fonctions, puis voir pourquoi Ces propriétés nous permettent de produire une signature vérifiable.
La fonction que nous allons utiliser ici s’appelle SHA-256.
Propriété 1 - Irréversibilité
Une fonction de hachage est un peu comme un hachoir à viande : vous mettez des steaks à une extrémité, et vous obtenez des hamburgers à l’autre - et il n’y a aucun moyen de récupérer ces steaks en commençant par le hamburger :
la fonction est effectivement irréversible !
Cela signifie que si nous prenons notre en-tête et notre charge utile et que nous les exécutons via cette fonction, personne ne pourra récupérer les données en regardant simplement la sortie.
Pour voir la sortie de SHA-256 par exemple, essayez-la avec ce calculateur de hachage en ligne, pour voir à quoi ressemble une sortie typique qui ressemble à ceci :
Cela signifie également que le hachage n’est pas du cryptage : le cryptage par définition est une action réversible - nous devons Récupérez l’entrée d’origine à partir de la sortie cryptée.
Une
autre chose importante à savoir sur le hachage est qu’il est reproductible, ce qui signifie que si nous hachons plusieurs fois le même capteur d’entrée et la même charge utile, nous obtiendrons toujours exactement le même résultat, petit à petit.
Cela signifie qu’étant donné une paire d’entrées et une sortie de hachage, nous pouvons toujours valider si une sortie donnée (par exemple une signature) est correcte car nous pouvons facilement reproduire le calcul - mais seulement si nous avons toutes les entrées.
Propriété 3 des fonctions de hachage - Pas de collisions Une
autre propriété intéressante des fonctions de hachage est que si nous lui soumettons plusieurs valeurs, nous obtenons toujours un résultat unique par valeur d’entrée.
Il n’y a effectivement aucune situation où deux entrées différentes produiront la même sortie - une entrée unique produit une sortie unique.
Cela signifie que si nous hachons la charge utile plus l’en-tête, nous obtenons toujours exactement le même résultat, et aucune autre donnée d’entrée n’aurait pu produire la même sortie de hachage - la sortie de hachage est en fait une représentation unique des données d’entrée.
Propriété 4 - Imprévisibilité
La dernière propriété que nous aborderons à propos des fonctions de hachage est qu’étant donné une sortie connue, il n’est pas possible de deviner l’entrée à l’aide d’une méthode d’approximation incrémentielle successive.
Supposons que nous ayons la sortie de hachage juste au-dessus et que nous essayions de trouver la charge utile qui l’a générée, en devinant une entrée et en inspectant la sortie pour voir si elle est proche du résultat attendu.
Ensuite, il nous suffit de modifier un caractère sur l’entrée, puis de vérifier à nouveau la sortie pour voir si nous nous sommes rapprochés, et si c’est le cas, nous répétons le processus jusqu’à ce que nous parvenions à deviner l’entrée.
Mais il n’y a que un problème :
avec les fonctions de hachage, cette stratégie ne fonctionnera pas !
En effet, dans une fonction de hachage, si nous changeons ne serait-ce qu’un seul caractère dans l’entrée (en fait, même un seul bit), en moyenne 50% des bits de sortie changeront !
Ainsi, même des différences minimes dans l’entrée créent une sortie complètement différente.
Tout cela semble intéressant, mais vous vous demandez probablement à ce stade : comment une fonction de hachage permet-elle une signature numérique alors ??
L’attaquant ne peut-il pas simplement prendre l’en-tête et la charge utile et falsifier la signature ?
N’importe qui peut appliquer la fonction SHA-256 et obtenir la même sortie et l’ajouter à la signature du JWT, n’est-ce pas ?
Comment utiliser les fonctions de hachage pour produire une signature ?
Cette dernière partie est vraie, n’importe qui peut reproduire le hachage d’un en-tête et d’une charge utile donnés.
mais la signature HS256 n’est pas seulement cela : au lieu de cela, ce que nous faisons, c’est que nous prenons l’en-tête, la charge utile et nous ajoutons également un mot de passe secret, puis nous hachons le tout ensemble.
Le résultat est un code d’authentification de message basé sur le hachage SHA-256, et un exemple de fonction qui fait cela est la fonction HMAC-SHA256, qui est utilisée dans les signatures HS256.
Le résultat de cette fonction ne peut être reproduit que par quelqu’un en possession de l’en-tête JWT, de la charge utile (qui sont lisibles par toute personne qui a saisi le jeton) ET du mot de passe.
Cela signifie que le hachage résultant est en fait une forme de signature numérique !
En effet, le résultat haché prouve que la charge utile a été créée puis signée par une personne en possession du mot de passe : il n’y aurait pas d’autre moyen pour quelqu’un de trouver ce hachage particulier.
Le hachage sert donc de preuve numérique infalsifiable que la charge utile est valide.
Le hachage est ensuite ajouté au message, afin de permettre au destinataire de l’authentifier : cette sortie hachée est appelée HMAC : Hash-Based Message Authentication Code, qui est une forme de signature numérique.
Et c’est exactement ce que nous faisons dans le cas des JWT : la dernière partie du JWT (après le deuxième point) est le hachage SHA-256 de l’en-tête plus la charge utile, encodée en Base64Url.
Comment valider une signature JWT ?
Ainsi, lorsque nous recevons un JWT signé HS256 sur notre serveur, nous devons également disposer exactement du même mot de passe, afin de pouvoir valider la signature et confirmer que le jeton Payload est bien valide.
Pour vérifier la signature, il suffit de prendre l’en-tête JWT plus la charge utile et de le hacher avec le mot de passe. Cela signifie que dans le cas du HS256, le récepteur JWT doit avoir exactement le même mot de passe que l’expéditeur.
Et si nous récupérons le même hachage que dans la signature, cela signifie que le jeton doit être valide, car seule une personne avec le mot de passe aurait pu trouver cette signature.
Et c’est ainsi, en général, que fonctionnent les signatures numériques et les HMAC. Voulez-vous le voir en action ?
Confirmation manuelle d’une signature JWT SHA-256
Prenons le même JWT que ci-dessus et supprimons la signature et le deuxième point, ne laissant que l’en-tête et la partie charge utile. Cela ressemblerait à ceci :
Maintenant, si vous copiez/collez cette chaîne dans un outil HMAC SHA-256 en ligne comme celui-ci, et que vous utilisez le mot de passe, nous récupérons la signature JWT !
Ou presque, nous récupérerons la version Base64 de celui-ci, qui a toujours un à la fin, et c’est proche mais pas identique à Base64Url :
Ce signe égal apparaîtrait comme dans une barre d’URL, donc c’est un peu désordonné, mais cela explique aussi la nécessité de Base64Url, si nous voulons envoyer des JWT en tant que paramètre d’URL.
Il n’y a pas beaucoup de convertisseurs Base64Url en ligne disponibles, mais nous pouvons toujours le faire dans la ligne de commande. Donc, pour vraiment confirmer cette signature HS256, voici un paquet npm qui implémente Base64Url, ainsi que la conversion de/vers Base64.
Le paquet NPM base64url
Utilisons-le ensuite pour convertir notre résultat en URL Base64 et confirmer complètement la signature et notre compréhension de son fonctionnement :
Alors enfin nous l’avons, cette chaîne est la signature JWT HS256 que nous essayions de reproduire :
C’est exactement la même signature que la JWT ci-dessus, personnage par personnage !
Alors félicitations, vous savez maintenant en profondeur comment fonctionnent les signatures JWT HS256 et vous serez en mesure de vous dépanner dans n’importe quelle situation à l’aide de ces outils et forfaits en ligne.
Pourquoi d’autres types de signatures alors ?
En résumé, c’est ainsi que les signatures JWT sont utilisées pour l’authentification, et HS256 n’est qu’un exemple d’un type de signature particulier. Mais il existe d’autres types de signatures, et celle qui est la plus couramment utilisée est : RS256.
Quelle est la différence ? Nous avons introduit le HS256 ici principalement parce qu’il simplifie beaucoup la compréhension de la notion de code MAC, et vous pourriez très bien le trouver en production dans de nombreuses applications.
Mais en général, il est préférable d’utiliser quelque chose comme la méthode de signature RS256 à la place, car comme nous allons l’apprendre dans la section suivante, elle présente de nombreux avantages par rapport à HS256.
Inconvénients des signatures HS256 Les signatures HS256
peuvent être forcées si la clé secrète d’entrée est faible, mais cela pourrait être dit de nombreuses autres technologies basées sur des clés.
Les signatures basées sur le hachage sont cependant particulièrement simples à forcer par rapport à d’autres alternatives, pour des tailles de clé de production typiques.
Mais plus que cela, un inconvénient pratique du HS256 est qu’il nécessite l’existence d’un mot de passe secret préalablement convenu entre le serveur qui émet les JWT et toute autre machine serveur consommant les JWT pour la validation et l’identification de l’utilisateur.
Cela
signifie que si nous voulons changer le mot de passe, nous devons le distribuer et l’installer à tous les nœuds du réseau qui en ont besoin, ce qui n’est pas pratique, c’est sujet aux erreurs et impliquerait un temps d’arrêt coordonné du serveur.
Cela pourrait même ne pas être faisable, disons qu’un serveur est géré par une équipe complètement différente ou même par une organisation tierce.
Pas de séparation entre la création et la validation du token
Tout se résume au fait qu’il n’y a pas de distinction entre la possibilité de créer des JWT et la possibilité de simplement les valider : avec HS256, tout le monde dans le réseau peut à la fois créer et valider des jetons car ils ont tous le mot de passe secret.
Cela signifie qu’il y a beaucoup plus d’endroits où le mot de passe peut être perdu ou volé par un attaquant, car le mot de passe doit être installé partout, et toutes les applications n’ont pas le même niveau de sécurité opérationnelle.
Une façon d’atténuer ce problème est de créer un mot de passe partagé par application, mais à la place, nous allons découvrir une nouvelle méthode de signature qui résout tous ces problèmes et que les solutions modernes basées sur JWT utilisent désormais par défaut : RS256.
La signature RS256 JWT
Avec RS256, nous allons toujours produire un code d’authentification de message comme auparavant, l’objectif est toujours de créer une signature numérique qui prouve qu’un JWT donné est valide.
Mais dans le cas de cette signature, nous allons séparer la possibilité de créer des jetons valides, que seul le serveur d’authentification devrait avoir, de la capacité de valider des jetons JWT, que seul notre serveur d’applications aurait intérêt à faire.
La façon dont nous allons y parvenir est que nous allons créer deux clés au lieu d’une :
- Il y aura toujours une clé privée mais cette fois elle ne sera possédée que par le serveur d’authentification, utilisée uniquement pour signer les JWT
- La clé privée peut être utilisée pour signer les JWT, mais elle ne peut pas être utilisée pour les valider
- Il existe une deuxième clé appelée clé publique, qui est utilisée par le serveur d’applications uniquement pour valider les JWT
- La clé publique peut être utilisée pour valider les signatures JWT, mais elle ne peut pas être utilisée pour signer de nouveaux JWT
- La clé publique n’a pas besoin d’être gardée privée et elle Ce n’est souvent pas le cas, car si l’attaquant l’obtient, il n’y a aucun moyen de l’utiliser pour falsifier des signatures
Présentation de la technologie de cryptage RSA
Lessignatures RS256 utilisent un type particulier de clés, appelées clés RSA. RSA est le nom d’un algorithme de chiffrement/déchiffrement qui prend une clé pour chiffrer et une seconde clé pour déchiffrer.
Notez que RSA n’est pas une fonction de hachage, car par définition, la sortie du chiffrement peut être inversée et nous pouvons récupérer le résultat initial.
Voyons à quoi ressemble une clé publique RSA :
encore une fois, cela semble un peu effrayant, mais il s’agit simplement d’une clé unique générée par un outil en ligne de commande comme openssl ou un utilitaire de génération de clés RSA en ligne comme celui-ci.
Encore une fois, cette clé peut être rendue publique, et elle est en fait généralement publiée, de sorte que l’attaquant n’a pas besoin de deviner cette clé : il l’a généralement déjà.
Mais il y a aussi la clé privée RSA correspondante :
la bonne nouvelle, c’est qu’il n’y a aucun moyen pour un attaquant de le deviner !
Encore une fois, rappelons-nous que les deux clés sont liées, quelle clé crypte l’autre et seule l’autre peut déchiffrer. Mais comment l’utiliser pour produire une signature ?
Pourquoi ne pas simplement chiffrer la charge utile avec RSA ?
Voici une tentative de création d’une signature numérique à l’aide de RSA : nous prenons l’en-tête et la charge utile, et les chiffrons à l’aide de RSA avec la clé privée, puis nous envoyons le JWT.
Le récepteur récupère le JWT, le déchiffre avec la clé publique et vérifie le résultat.
Si le processus de déchiffrement fonctionne et que la sortie ressemble à une charge utile JSON, cela signifie que c’est le serveur d’authentification qui a créé ces données et les a chiffrées. Il doit donc être valide, n’est-ce pas ?
C’est en effet vrai, et cela être suffisant pour prouver que le jeton est correct. Mais ce n’est pas ce que nous faisons pour des raisons pratiques.
Le processus de chiffrement RSA est relativement lent par rapport à une fonction de hachage, par exemple. Pour les charges utiles de plus grande taille, cela peut être un problème, et ce n’est qu’une des raisons.
Alors, que faire alors, comment les signatures HS256 utilisent-elles réellement RSA dans la pratique ?
Utilisation de RSA et SHA-256 pour signer un JWT (RSA-SHA256)
En pratique, nous prenons l’en-tête et la charge utile et les hachons en premier, en utilisant par exemple SHA-256.
C’est quelque chose de très rapide à faire, et nous obtenons une représentation unique des données d’entrée qui est beaucoup plus petite que les données réelles elles-mêmes.
Nous prenons ensuite la sortie de hachage et la cryptons au lieu de l’ensemble des données (en-tête plus charge utile) à l’aide de la clé privée RSA, qui nous donne la signature RS256 !
Nous l’ajoutons ensuite au JWT en tant que dernier des 3 parties, et nous l’envoyons.
Comment le récepteur vérifie-t-il les signatures RS256 ?
Le récepteur du JWT va alors :
- prendre l’en-tête et la charge utile, et hacher tout avec SHA-256
- déchiffrer la signature à l’aide de la clé publique, et obtenir le hachage de signature
- le récepteur compare le hachage de signature avec le hachage qu’il a lui-même calculé sur la base de l’en-tête et de la charge utile
Les deux hachages correspondent-ils ? Cela prouve alors que le JWT a bien été créé par le serveur d’authentification !
N’importe qui aurait pu calculer ce hachage, mais seul le serveur d’authentification aurait pu le chiffrer avec la clé privée RSA correspondante.
Pensez-vous qu’il doit y avoir plus que cela ? Confirmons cela et apprenons à résoudre les problèmes de signatures RS256 en cours de route.
Confirmation manuelle d’une signature JWT RS256
Commençons par prendre l’exemple d’un JWT signé avec RS256 de jwt.io :
Comme nous pouvons le voir, il n’y a pas de différence visuelle immédiate par rapport à un JWT HS256, mais celui-ci a été signé avec la même clé privée RSA que celle illustrée ci-dessus.
Isolons maintenant l’en-tête et la charge utile uniquement, et supprimons la signature :
tout ce que nous avons à faire maintenant est de hacher ceci avec SHA-256, et de le chiffrer avec RSA à l’aide de la clé privée RSA illustrée ci-dessus.
Le résultat devrait être la signature JWT ! Vérifions si c’est le cas à l’aide du module Crypto intégré à Node. Il n’est pas nécessaire d’effectuer une installation externe, celle-ci est intégrée à Node.
Ce module est livré avec une fonction RSA-SHA256 intégrée et de nombreuses autres fonctions de signature que nous pouvons utiliser pour essayer de reproduire des signatures.
Pour ce faire, la première chose dont nous avons besoin est de prendre la clé privée RSA et de l’enregistrer dans un fichier texte, nommé.
Ensuite, sur la ligne de commande, nous exécutons le shell node et exécutons ce petit programme :
Si vous utilisez un JWT différent du JWT de test que nous avons utilisé, alors vous devez copier/coller uniquement les deux parties de l’appel, sans la signature JWT.
Et voici ce que nous obtenons en retour :
Ce qui est complètement différent de la signature JWT !! Mais attendez une seconde : il y a des barres obliques ici, des signes égaux : il ne serait pas possible de mettre une URL sans s’échapper davantage.
C’est parce que nous avons créé la version Base64 de la signature, et ce dont nous avons besoin à la place, c’est de la version Base64Url de celle-ci. Alors convertissons-le :
Et voici ce qui en revient :
C’est-à-dire exactement, petit à petit, la signature RS256 que nous essayions de créer !
Cela prouve notre compréhension des signatures JWT RS256, et nous savons maintenant comment les dépanner si nécessaire.
En résumé, les signatures JWT RS256 sont simplement un hachage SHA-256 chiffré RSA de l’en-tête et de la charge utile.
Nous savons donc maintenant comment fonctionnent les signatures RS256, mais pourquoi ces signatures sont-elles meilleures que les signatures HS256 ?
Signatures RS256 vs HS256 - Pourquoi utiliser RS256 ?
Avec RS256, l’attaquant peut facilement effectuer la première étape du processus de création de signature, qui consiste à créer le hachage SHA-256 basé sur les valeurs d’un en-tête JWT et d’une charge utile volés.
Mais à partir de là, pour recréer une signature, il devrait forcer RSA, ce qui est impossible pour une bonne taille de clé.
Mais ce n’est pas la raison la plus pratique pour laquelle nous voudrions choisir RS256 plutôt que HS256, pour la plupart des applications.
Avec RS256, nous savons également que la clé privée qui a le pouvoir de signer des jetons n’est conservée que par le serveur d’authentification, où elle est beaucoup plus sûre - donc RS256 signifie moins de chances de perdre la signature Clé privée.
Mais il y a une raison pratique beaucoup plus importante de choisir RS256 : la rotation simplifiée des touches.
Rappelons
que la clé publique utilisée pour valider les tokens peut être publiée n’importe où, et que l’attaquant ne peut en pratique rien en faire.
Après tout, à quoi cela servirait-il à un attaquant de pouvoir valider un JWT volé ? Un attaquant veut être en mesure de falsifier des JWT, pas de les valider.
Cela ouvre la possibilité de publier la clé publique sur un serveur sous notre contrôle.
Les serveurs d’applications n’ont alors qu’à se connecter à ce serveur pour récupérer la clé publique, et la vérifier à nouveau périodiquement au cas où elle aurait changé, soit en raison d’une urgence ou d’une rotation périodique des clés.
Il n’est donc pas nécessaire d’arrêter le serveur d’applications et le serveur d’authentification en même temps, et de mettre à jour les clés n’importe où en une seule fois.
Mais comment la clé publique peut-elle être publiée ? Voici un format possible.
Points de terminaison JWKS (JSON Web Key Set)
Il existe de nombreux formats pour publier des clés publiques, mais en voici un qui vous semblera familier : JWKS qui est l’abréviation de Json Web Key Set.
Il existe des packages npm très faciles à utiliser pour consommer ces points de terminaison et valider les JWT, comme nous le verrons dans la deuxième partie.
Il s’agit de points de terminaison qui peuvent publier une série de clés publiques, et pas une seule.
Si vous êtes curieux de savoir à quoi ressemble ce type de points de terminaison, jetez un coup d’œil à cet exemple en direct, voici ce que nous recevons en réponse à une requête HTTP GET :
La propriété est l’identificateur de clé et est la représentation d’une clé publique particulière.
Ce qui est génial avec ce format, c’est qu’il est standard, donc nous n’avons qu’à avoir l’URL du point de terminaison, et une bibliothèque qui consomme JWKS - cela devrait nous donner une clé publique prête à l’emploi pour valider les JWT, sans avoir à l’installer sur notre serveur.
Les JWT sont souvent associés à des sites Internet publics et à des solutions de connexion sociale. Mais qu’en est-il de l’intranet, des applications internes ?
Les JWT dans les
JWT d’entreprise sont également applicables à l’entreprise, en tant qu’excellente alternative à la configuration typique de pré-authentification qui est un passif de sécurité connu.
Dans la configuration de pré-authentification utilisée par de nombreuses entreprises, nous exécutons nos serveurs d’applications derrière un proxy sur un réseau privé, et récupérons simplement l’utilisateur actuel à partir d’un en-tête HTTP.
L’en-tête HTTP qui identifie l’utilisateur est généralement rempli par un élément centralisé du réseau, généralement une page de connexion centralisée installée sur un serveur proxy qui s’occupera de la session de l’utilisateur.
Ce serveur bloquera l’accès à la si la session a expiré et authentifiera les utilisateurs après la connexion.
Après cela, il transmettra toutes les requêtes au serveur d’applications et ajoutera simplement un en-tête HTTP pour identifier l’utilisateur.
Le problème est qu’avec cette configuration en pratique, toute personne à l’intérieur du réseau peut facilement se faire passer pour un utilisateur simplement en définissant le même en-tête HTTP !
Il existe des solutions pour cela, comme la liste blanche de l’IP du serveur proxy au niveau du serveur d’applications, ou l’utilisation d’un certificat client, mais en pratique, la plupart des entreprises n’ont pas mis en place ces mesures.
L’idée de
la pré-authentification est cependant bonne, car cette configuration signifie que le développeur d’applications n’a pas à implémenter lui-même les fonctionnalités d’authentification sur chaque application, ce qui permet de gagner du temps et d’éviter la sécurité potentielle Insectes.
Ne serait-il pas formidable d’avoir la commodité de la configuration de pré-authentification, sans avoir à compromettre la sécurité et à rendre l’authentification de notre application facilement contournable, même si ce n’est qu’à l’intérieur d’un réseau privé ?
C’est simple à faire si nous mettons JWT dans l’image : au lieu de simplement mettre le nom d’utilisateur dans l’en-tête comme nous le faisons habituellement dans la pré-authentification, faisons de cet en-tête HTTP un JWT.
Mettons ensuite le nom d’utilisateur à l’intérieur de la charge utile de ce JWT, signé par le serveur d’authentification.
Le serveur d’applications, au lieu de simplement prendre le nom d’utilisateur de l’en-tête, va d’abord valider le JWT :
- si la signature est correcte, alors l’utilisateur est correctement authentifié et la requête passe
- sinon, le serveur d’applications peut simplement rejeter la requête Le
résultat est que nous avons maintenant l’authentification qui fonctionne correctement, même à l’intérieur du réseau privé !
Nous n’avons plus besoin de faire confiance aveuglément à l’en-tête HTTP contenant le nom d’utilisateur. Nous pouvons nous assurer que cet en-tête HTTP est bien valide et émis par le proxy, et qu’il ne s’agit pas d’un attaquant essayant de se connecter en tant qu’autre utilisateur.
Conclusions
Dans cet article, nous avons une idée générale de ce que sont les JWT et de la manière dont ils sont utilisés pour l’authentification. Les JWT sont simplement des charges utiles JSON avec une signature facilement vérifiable et impardonnable.
Encore une fois, il n’y a rien dans les JWT qui soit spécifique à l’authentification, nous pourrions les utiliser pour envoyer n’importe quelle revendication sur le réseau.
Une autre utilisation courante liée à la sécurité pour les JWT si Autorisation : on peut par exemple mettre dans la charge utile la liste des rôles d’autorisation pour l’utilisateur : Utilisateur en lecture seule, Administrateur, etc.
Dans le prochain article de cette série, nous allons apprendre comment implémenter l’authentification dans un Application angulaire à l’aide de JWT.
J’espère que vous avez apprécié cet article, si vous avez des questions ou des commentaires, n’hésitez pas à me le faire savoir dans les commentaires ci-dessous et je reviendrai vers vous.
Si vous souhaitez en savoir plus sur la sécurisation d’une application Angular, nous vous recommandons de consulter le cours de sécurité Angular, où les JWT sont couverts beaucoup plus en détail.
Pour être averti lorsque d’autres articles comme celui-ci sortent, je vous invite à vous abonner à notre newsletter :
Si vous commencez tout juste à apprendre Angular, jetez un coup d’œil au cours Angular pour débutants :
Liens connexes
Le manuel JWT par Auth0
Naviguer dans RS256 et JWKS
Brute Forcing HS256 est possible : L’importance d’utiliser des clés fortes dans la signature du
jeu de clés Web JSON JWT (JWKS)
Jetez également un coup d’œil à d’autres articles populaires qui pourraient vous intéresser :