Il est très facile de générer un jeton JWT qui présente les caractéristiques d’un jeton valide, mais qui est pourtant un faux. Dans cet article, nous verrons comment se protéger contre cette situation.
Un jeton JWT est une chaîne de caractère en trois parties séparées chacune par un point:
- La première partie est le header ou l’entête. Elle contient les métadonnées sur la signature.
- La deuxième partie est le payload, ou charge utile. Elle contient les informations utiles du jetons.
- La troisième partie est la signature numérique du jeton. Elle joue un rôle important comme nous le verrons par la suite.
Un jeton JWT est donc sous la forme header.payload.signature. Chaque partie est encodée en base 64. En voici un exemple:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
JWT et OAuth2
Les protocoles OpenIDConnect et OAuth2 utilisent massivement les jetons JWT. Le succès de ces protocoles a donc entraîné la popularisation de l’utilisation des jetons JWT.
Pour rappel, OAuth 2 est un protocole d’autorisation qui sert à protéger l’accès aux ressources web. Une application qui implémente OAuth2 conditionne l’accès à ses ressources par la présentation d’un jeton JWT qui contient les droits qui autorisent cet accès. Le jeton JWT est forgé par une entité de confiance qui s’appelle le Serveur d’Autorisation.
Lorsqu’une application reçoit une requête avec un jeton JWT, elle doit impérativement vérifier la signature du jeton en premier lieu, avant d’entreprendre quoi que ce soit.
Mécanique de l’attaque et moyen de protection
Un jeton JWT n’étant pas chiffré, son contenu est librement accessible. Il est donc possible de consulter un jeton existant et de forger un jeton JWT en tout point identique au couple header.payload de ce jeton. Chaque application doit impérativement se prémunir contre cette possibilité.
Pour s’en protéger, l’application doit s’assurer que chaque jeton JWT qu’elle reçoit provient du serveur d’autorisation auquel elle fait confiance. Pour cela, elle doit vérifier l’authenticité de la troisième partie du jeton: la signature.
En effet, tout serveur d’autorisation signe numériquement avec une clé privée chaque jeton JWT qu’il émet. Cette signature est directement liée à la clé privée utilisée par le serveur ainsi qu’au contenu du jeton:
Signature = fonction(PK, header, payload).
A chaque réception d’un jeton JWT, l’application doit vérifier que le jeton provient du serveur d’autorisation attendu. Elle aura besoin pour cela de la clé publique correspondant à la clé privée utilisée pour la signature, ainsi que l’algorithme utilisé. L’algorithme de signature est dans l’entête du jeton. La clé publique est librement mise à disposition par le Serveur d’Autorisation
Les garanties offertes par la signature
La signature du jeton JWT garantit à la fois son authenticité et son intégrité. Cela signifie que lorsque la signature est valide, on sait avec certitude quel Serveur d’Autorisation a émis le jeton, et aussi que son contenu n’a pas été altéré.
Il y a une autre garantie importante offerte par la signature du jeton: il s’agit de la non-répudiation. Cela signifie qu’un Serveur Autorisation ne peut nier avoir émis un jeton JWT comportant sa signature.
Un autre élément important à vérifier en plus de la signature
Un jeton JWT a une date création et une date d’expiration. Une fois l’authentification de la signature confirmée, il convient aussi de vérifier que le jeton n’est pas expiré, et aussi qu’il n’a pas été émis dans le futur…
Conclusion
Dans cet article, nous avons abordé les vérifications minimales à faire lorsqu’on reçoit un jeton JWT. Ces vérifications sont absolument indispensables pour vous protéger contre les attaques à base de jetons JWT frauduleux. Selon votre cas d’usage, d’autres contrôles peuvent être nécessaires.
Si cet article vous a été utile, N’hésitez pas à laisser un commentaire et à le partager autour de vous.
