Analyse des menaces d'authentification brisée des utilisateurs qui pèsent sur les jetons Web JSON
Synthèse
Les chercheurs d'Akamai ont analysé les jetons Web JSON (JWT) en tant que vecteur d'attaques d'authentification brisée des utilisateurs, qui figurent dans la liste des 10 principaux risques pour la sécurité des API selon l'OWASP (Open Web Application Security Project),et ont découvert différents scénarios dans lesquels se produisent les tendances et menaces JWT.
Les JWT sont responsables de la sécurisation des API en émettant des jetons (généralement entre les clients et les serveurs) pour procéder à la vérification des utilisateurs en toute sécurité. Ces jetons sont l'un des formats de vérification les plus courants et contiennent des informations à partager sous forme d'objets JSON.
Bien que chaque jeton ne soit pas chiffré, il est codé et possède une signature de vérification. Nous avons examiné certaines des nombreuses menaces qui pèsent sur les JWT en raison d'une mauvaise mise en œuvre ou d'une faible entropie et de clés secrètes courtes.
Le piratage de compte, l'élévation des privilèges et les fuites de données représentent trois risques potentiels majeurs auxquels les entreprises et les utilisateurs JWT sont confrontés lorsqu'ils choisissent un JWT comme jeton de choix dans une API. Dans notre trafic, nous avons observé que la plupart des JWT utilisent un algorithme symétrique, même si cette pratique est en théorie moins sûre.
Dans ce billet, nous proposons des meilleures pratiques sur la façon de gérer ces menaces JWT.
Introduction
Les JWT sont un schéma de jeton largement utilisé, relativement facile à adopter, qui masque de nombreux risques. Ces risques doivent être pris en compte lors de la mise en œuvre et de la sécurisation des JWT. L'un des risques les plus importants pour les JWT, qui figure dans la liste des 10 principaux risques pour la sécurité des API selon l'OWASP, est l'authentification brisée des utilisateurs.
Une authentification brisée des utilisateurs se produit lorsqu'une API ne vérifie pas correctement les informations d'identification et l'identité de l'utilisateur qui effectue la demande. Malheureusement, il s'agit d'une vulnérabilité courante observée pour les JWT et qui peut conduire un attaquant à usurper l'identité de l'utilisateur ou à accéder au compte d'un autre utilisateur, entraînant ainsi une élévation des privilèges et des fuites de données.
Protéger le pipeline
Un JWT est un jeton d'authentification couramment utilisé dans les API et les applications Web. Dans notre trafic, nous avons observé que les applications Web adoptent de plus en plus d'API et les exposent au client, d'où la nécessité croissante d'une authentification en toute transparence sur les différents terminaux API.
L'API est le principal pipeline d'une entreprise. Elle détient les mécanismes d'authentification et d'autorisation, interroge les bases de données et expose la plupart des fonctions de l'entreprise. Pour cette raison, les menaces JWT sont plus dangereuses dans les API. Dans ce billet de blog, nous allons présenter les principes de base des JWT, six menaces qui pèsent sur les JWT et comment traiter ces menaces.
Les principes de base des JWT
JWT est un format permettant d'envoyer des données JSON signées pour transmettre des données dans des applications Web, des applications pour mobile et des API. Il est principalement utilisé pour l'authentification uniquement. La structure JWT comprend trois éléments : l'en-tête (également appelé « en-tête JOSE »), la charge utile et la signature, tous ces éléments étant séparés par un point (Figure 1).
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIiLCJpYXQiOjE2NzYyMTc5NTAsImV4cCI6MTcwNzc1Mzk1MCwiYXVkIjoiYWthbWFpLWJsb2ciLCJzdWIiOiIiLCJjb21wYW55IjoiQWthbWFpIiwidXNlciI6IkFrYW1haS1yZWFkZXIiLCJhZG1pbiI6Im5vIn0.kMPz3Z7BSlBTJKijD8bcrpzTZejX7VCZ77w5oQwJO6I
Figure 1 : exemple des trois éléments de la structure JWT
L'en-tête et la charge utile
L'en-tête et la charge utile sont des recommandations codées en Base64, adaptées aux URL et spécifiées par l'IETF pour les champs (Figure 2). « Codées » signifie qu'elles ne sont pas directement lisibles à l'œil nu, mais que le serveur peut facilement les décoder. L'objectif de cette démarche est de garantir l'intégrité et la convivialité des données, tout en s'assurant qu'elles restent « adaptées aux URL ». De cette façon, il n'y aura pas de caractères se chevauchant comme ceux utilisés par les navigateurs Web.
L'en-tête JOSE est utilisé pour le chiffrement Web JWT et JSON (JWE), qui est essentiellement un JWT chiffré qui aide à éviter les attaques JWT les plus courantes. Le champ qui spécifie la méthode de jeton choisie est « typ » (typ:JWT/JWE). La charge utile peut contenir des champs enregistrés (demandés par l'Internet Assigned Numbers Authority) ou des champs personnalisés, selon la mise en œuvre.
Figure 2 : JWT codé
La signature
L'objectif de la signature est de vérifier le jeton, ce qui signifie que le serveur a falsifié le jeton et que les données n'ont pas changé depuis la création du jeton.
La création de la signature compte deux étapes :
Application d'un algorithme de chiffrement (par exemple, MAC) sur l'en-tête et la charge utile, tous deux séparés par un point (l'algorithme utilise une clé secrète)
Application d'un algorithme de hachage (par exemple, SHA256) sur l'en-tête et la charge utile chiffrés
Lors de l'utilisation d'un JWT, le serveur vérifie la signature afin de valider le jeton lui-même. (Plus loin dans ce billet, je vais expliquer les différents algorithmes utilisés à des fins de validation.)
Les JWT sont largement utilisés pour l'authentification dans les applications Web en raison de leur facilité d'utilisation (y compris à grande échelle) et de leur simplicité de mise en œuvre, mais aussi parce que les données requises du serveur sont enregistrées côté client. Mais les JWT comportent des risques, même s'ils sont signés. JWT utilise du texte brut et chaque mise en œuvre est constituée de différents champs de charge utile. La surface d'attaque est donc vaste, ce qui laisse beaucoup de place aux erreurs.
En explorant certaines des menaces les plus courantes et les plus intéressantes auxquelles sont confrontés les JWT, nous pouvons être plus conscients des vulnérabilités, détecter plus facilement les comportements malveillants, mieux atténuer les risques et préparer les mesures de sécurité nécessaires pour nous protéger contre les failles d'exploitation potentielles.
Notre objectif est de proposer aux utilisateurs une approche d'utilisation des JWT plus sécurisée et de fournir aux professionnels et administrateurs de la sécurité les outils et les recommandations nécessaires pour les aider à faire preuve de diligence raisonnable.
Six menaces qui pèsent sur les JWT
1. Autoriser le serveur à utiliser un jeton sans validation
Étant donné qu'un JWT est signé au lieu d'être chiffré, celui-ci doit être validé avant toute utilisation. Dans le scénario de menace le plus élémentaire, dans lequel la validation d'une application échoue, un attaquant peut modifier la charge utile (par exemple, élévation des privilèges)sans modifier la signature, ou même la supprimer et obtenir des autorisations supérieures.
Une autre méthode consiste à utiliser le paramètre « alg » dans l'en-tête, qui représente l'algorithme utilisé pour signer le jeton. « Aucun » est une valeur légitime (et le JWT est nommé JWT non sécurisé), de sorte que tout le monde peut facilement signer le jeton. Au niveau du back-end, il est également possible de mettre en œuvre une vérification des JWT.
Commencez cette approche en recherchant le champ « alg » dans l'en-tête. Ensuite, utilisez l'algorithme spécifié pour vérifier le jeton. L'algorithme « Aucun » signifie qu'aucune signature ni vérification n'est nécessaire pour ce jeton. Toute modification de la charge utile, de l'en-tête (en alg:none) et de l'auto-signature (suppression de la signature) du jeton entraînera une attaque réussie.
Exemple
La Figure 3 montre un exemple de JWT décodé.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZXhhbXBsZSBuYW1lIiwiaWF0Ij
oxNjU5MjM5MDIyfQ.PrhAp2DUWXoL01_odyLATuzrwn5rMtY1IVsP8y4LH5E
decoded:
{
"alg": "HS256",
"typ": "JWT"
}
.{
"name": "example name",
"iat": 1659239022
}
Figure 3 : exemple de JWT décodé
Nous supposons que le point de terminaison API utilise le champ « alg » de la charge utile comme algorithme choisi pour la vérification.
Toutefois, nous aimerions modifier le JWT (Figure 4). De cette façon, nous réussissons à falsifier un JWT valide d'un autre utilisateur.
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiZXhhbXBsZSBuYW1lIiwiaWF0Ijo
xNjU5MjM5MDIyfQ.
decoded:
{
"alg": "none",
"typ": "JWT"
}
.{
"name": "other person's name",
"iat": 1659239022
}
Figure 4 : JWT modifié pour exploiter le champ alg:none.
Pratique recommandée : celle-ci est simple : effectuez toujours une validation en utilisant un algorithme prédéfini codé en dur avant d'utiliser le jeton. N'utilisez pas le paramètre alg comme pointeur pour l'algorithme de vérification.
2. Utiliser la même clé privée pour différentes applications
De nombreuses entreprises choisissent d'avoir un enregistrement distinct pour différentes applications. L'utilisation de la même clé privée créera un jeton valide dans les deux applications, mais avec un ID utilisateur différent. Dans ce cas, il s'agit de faire une demande à une deuxième application avec le jeton d'application de la première, puis de prendre le contrôle d'un compte (pas celui de votre choix) (Figure 5).
Pratique recommandée : il s'agit d'une autre règle de base simple : lorsque vous séparez les ID utilisateur, utilisez des clés privées différentes.
3. Utiliser un algorithme de signature faible
Il existe deux familles principales d'algorithmes : symétrique (HSXXX) et asymétrique (RSXXX, ESXXX, PSXXX). Un algorithme symétrique nécessite une clé secrète partagée, tandis qu'un algorithme asymétrique requiert des clés privées et publiques (Tableau 1).
Symétrique |
|||
---|---|---|---|
HSXXX |
HMAC + SHA |
Algorithme relativement faible |
Utilise une clé secrète partagée |
Asymétrique |
|||
RSXXX |
RSA + SHA |
Algorithme plus sécurisé |
Utilise des clés privées et publiques |
ESXXX |
ECDSA + SHA |
Algorithme le plus sécurisé des trois |
Utilise des clés privées et publiques |
Tableau 1 : les deux principales familles d'algorithmes
Du point de vue de l'attaquant, un algorithme symétrique est plus facile à attaquer en force. Il n'est pas nécessaire de collecter des clés publiques et le temps de calcul est aussi efficace que possible. Dans notre trafic, nous avons observé que les algorithmes symétriques sont plus largement utilisés que les algorithmes asymétriques (Figure 6).
En théorie, les algorithmes symétriques nécessitent moins de calcul, de sorte qu'à grande échelle, ils peuvent être plus performants que les algorithmes asymétriques.
Pratique recommandée : utilisez des algorithmes asymétriques. Nous vous recommandons d'utiliser l'algorithme ECDSA, qui est actuellement le choix le plus sûr (au niveau du chiffrement). Une clé symétrique correctement sécurisée est acceptable si la clé secrète est à entropie élevée et suffisamment longue.
4. Choisir une clé privée courte et/ou à faible entropie
Une clé privée courte et/ou à faible entropie pourrait faire l'objet d'une attaque en force, le tout de manière rapide et à faible coût. Il existe un logiciel de craquage facile à utiliser qui peut être installé sur des environnements cloud hautes performances avec des unités de traitement graphique (GPU). Les performances des unités de traitement graphique augmentent rapidement et ont un effet sur les capacités de craquage. Il est possible de craquer les cartes graphiques haut de gamme aujourd'hui près de 2,5 fois plus vite qu'il y a trois ans.
Le tableau 2 compare le nombre de jours nécessaires pour craquer une clé privée à huit caractères (quelle que soit son entropie) il y a trois ans et aujourd'hui.
Carte graphique haut de gamme |
Jours nécessaires pour la craquer |
---|---|
Il y a trois ans |
10,5 jours |
Aujourd'hui |
4,5 jours |
Tableau 2 : nombre de jours nécessaires pour craquer une clé privée à huit caractères
Il y a quelques années, il fallait environ 24 heures pour craquer une clé privée à sept caractères. Désormais, moins de 90 minutes suffisent. La particularité de cette attaque est qu'elle fonctionne hors ligne. Ainsi, l'entreprise n'a aucune chance de se protéger, ni même de savoir qu'elle subit une telle attaque.
Imaginez un instant que vous êtes un attaquant parrainé par un État qui créerait un système orchestré pour cela. Détenir la clé privée du JWT signifie que l'attaquant peut falsifier un jeton signé et usurper l'identité de tout autre utilisateur en connaissant simplement son ID.
Pratique recommandée : choisissez une clé privée longue (au moins 10 caractères) et à entropie élevée. Nous vous recommandons d'utiliser un générateur de clés secrètes RSA.
5. Conserver des données sensibles dans la charge utile d'un JWT
Les JWT sont codés en Base64 et adaptés aux URL, de sorte que la charge utile n'est pas chiffrée. Le stockage des noms de bases de données, des ID incrémentiels (de toutes sortes) ou de tous les champs et données internes du serveur crée une exposition excessive des données, ce qui peut aider un attaquant dans d'autres vecteurs d'attaque (par exemple, une autorisation brisée au niveau de l'objet).
Pratique recommandée : ne stockez pas de données sensibles dans un JWT. Si vous avez besoin de stocker des données sensibles, utilisez JWE.
6. Confondre les clés
Avec les algorithmes asymétriques, une clé privée permet de falsifier le JWT (la partie signature) et une clé publique permet de valider le JWT. Un attaquant peut remplacer l'algorithme spécifié dans l'en-tête par un algorithme symétrique (par exemple, HS256) et créer une signature à l'aide de la clé publique légitimement utilisée par le serveur à des fins de vérification.
Dans ce scénario, le back-end non correctement mis en œuvre utilisera la clé publique et exécutera l'algorithme symétrique (comme spécifié par l'attaquant dans l'en-tête) pour vérifier avec succès le JWT qui a été falsifié par l'attaquant.
Exemple
La Figure 7 illustre le processus de falsification d'un nouveau JWT du serveur et la Figure 8 illustre le processus de vérification des JWT du serveur.
Dans la dernière partie de la vérification, une erreur d'affichage dans la comparaison peut se produire pour l'une des deux raisons suivantes (ou les deux) :
L'en-tête et la charge utile ont été modifiés, mais pas la signature
Le bon algorithme ou la bonne clé est mal configuré(e)
La Figure 9 illustre une attaque de confusion des clés.
Étape finale : le serveur vérifie le jeton en suivant le processus illustré dans la Figure 8, dans lequel le serveur approuve le champ alg. Il vérifie le jeton en exécutant l'algorithme HS256 avec la clé publique comme clé secrète, ce qui est exactement ce que l'attaquant avait prévu.
Pratique recommandée : utilisez des algorithmes prédéfinis dans le processus de vérification et n'approuvez pas les données saisies par l'utilisateur.
Conclusion
JWT est le jeton d'authentification le plus courant. Il permet d'utiliser de nombreuses applications Web et API tout en étant authentifié, sans se connecter fréquemment. Cependant, les JWT sont à l'origine de nombreuses menaces car ils ne sont ni chiffrés ni mis en œuvre dans un esprit de sécurité.
La puissance informatique évolue rapidement, ce qui met en danger les clés secrètes faibles, qui peuvent alors être craquées en quelques jours au lieu de quelques années. Dans le cas des JWT, ce type d'attaque peut s'exécuter hors ligne sans que l'entreprise n'en ait connaissance.
Les algorithmes symétriques sont le type d'algorithme le plus courant, ce qui facilite la vie des attaquants.
Il existe également des menaces plus complexes, telles que les attaques d'authentification, mais il est difficile pour les attaquants d'automatiser les attaques d'authentification. Les vecteurs d'attaques JWT simples, cependant, peuvent être automatisés et massivement exploités.
Pour ces raisons (et bien d'autres), il est essentiel que les utilisateurs soient conscients des vulnérabilités des JWT et des meilleures pratiques de sécurité à mettre en œuvre pour se protéger contre les failles d'exploitation potentielles. Nous espérons que cette analyse vous sera utile pour protéger les JWT contre toute authentification brisée des utilisateurs, l'un des 10 principaux risques pour la sécurité des API selon l'OWASP.