Comment sécuriser les jetons JWT : Guide des meilleures pratiques
Les jetons Web JSON (JWT) sont devenus le standard de l'industrie pour l'authentification sans état. Ils permettent aux serveurs de vérifier l'identité d'un utilisateur sans stocker de données de session sur le serveur lui-même. Cependant, cette nature sans état introduit des risques de sécurité spécifiques si elle n'est pas implémentée correctement. Dans ce guide, nous explorerons comment sécuriser correctement les jetons JWT pour protéger les données utilisateur et maintenir l'intégrité de l'application.
Comprendre la structure JWT
Avant de plonger dans les mesures de sécurité, il est crucial de comprendre les trois parties d'un JWT : l'en-tête (Header), la charge utile (Payload) et la signature.
- En-tête : Contient l'algorithme utilisé pour signer le jeton (par exemple, HS256, RS256).
- Charge utile : Contient les revendications (données sur l'utilisateur, comme l'ID et le rôle).
- Signature : Assure que le jeton n'a pas été altéré.
Comme la charge utile est encodée en base64, elle est lisible par n'importe qui qui intercepte le jeton. C'est pourquoi des mesures de sécurité comme HTTPS et la validation de signature sont incontournables.
1. Toujours utiliser HTTPS
L'étape la plus fondamentale pour sécuriser n'importe quel jeton est de s'assurer qu'il est transmis sur un canal sécurisé. Si un JWT est envoyé sur HTTP, un attaquant sur le réseau peut intercepter et lire la charge utile du jeton, risquant potentiellement d'extraire des informations utilisateur sensibles.
BBVA souligne que l'utilisation d'HTTPS est obligatoire pour prévenir les attaques d'interception (Man-in-the-Middle). Ce chiffrement garantit que le jeton reste confidentiel du moment où il quitte le client jusqu'à son arrivée sur le serveur.
2. Sécurisez vos secrets de signature
La signature est la seule partie du JWT qui prouve son authenticité. Pour générer une signature valide, vous avez besoin d'une clé secrète (pour les algorithmes symétriques) ou d'une clé privée (pour les algorithmes asymétriques).
Ne codez pas en dur les secrets
L'une des erreurs les plus courantes que font les développeurs est de coder en dur la clé secrète directement dans le code source. Si votre code est poussé dans un dépôt public (comme GitHub), le secret est exposé. H2S Media déconseille cette pratique, recommandant plutôt d'utiliser des variables d'environnement pour stocker les secrets. Cela garde les données sensibles séparées de la logique de votre application et empêche l'exposition accidentelle.
Faites tourner vos secrets régulièrement
Même si vos secrets sont stockés en toute sécurité, ils doivent être tournés périodiquement. Si un secret est compromis, un attaquant peut forger des jetons indéfiniment. Une rotation régulière limite la fenêtre d'opportunité pour un attaquant.
3. Choisissez le bon mécanisme de stockage
Où vous stockez le JWT du côté client est une décision de sécurité critique. Les deux options principales sont LocalStorage et les cookies HttpOnly.
Les risques de LocalStorage
Stocker des JWT dans localStorage les rend accessibles à tout JavaScript s'exécutant sur la page. Si votre application a une vulnérabilité de script intersites (XSS), un attaquant peut facilement voler le jeton et se faire passer pour l'utilisateur. MakeUseOf souligne que bien que localStorage soit pratique, il est vulnérable aux attaques XSS.
La sécurité des cookies HttpOnly
Les cookies HttpOnly ne sont pas accessibles via JavaScript. Cela les rend immunisés contre les attaques XSS qui tentent de voler le jeton. Pour une sécurité maximale, surtout dans les applications gérant des données sensibles, stocker le JWT dans un cookie HttpOnly est l'approche recommandée. Cette méthode aide également à atténuer les attaques CSRF (Cross-Site Request Forgery) si elle est combinée avec des attributs SameSite appropriés.
4. Implémentez des temps d'expiration courts
Les JWT sont conçus pour être sans état, ce qui signifie qu'ils sont valides jusqu'à leur expiration. Cependant, plus un jeton est valide longtemps, plus le risque est élevé s'il est intercepté. AWS recommande l'utilisation de temps d'expiration courts pour les jetons d'accès. En gardant le TTL (Time To Live) court, vous limite les dégâts qu'un attaquant peut faire s'il parvient à voler le jeton.
Le modèle des jetons de rafraîchissement
Pour maintenir une expérience utilisateur fluide sans augmenter les risques de sécurité, les développeurs utilisent souvent une combinaison de jetons d'accès à courte durée de vie et de jetons de rafraîchissement à plus longue durée de vie. Le jeton d'accès accorde un accès immédiat à l'API, tandis que le jeton de rafraîchissement est utilisé pour obtenir un nouveau jeton d'accès. Les jetons de rafraîchissement doivent être stockés en toute sécurité, souvent dans des cookies HttpOnly, et avoir une durée de vie plus longue.
5. Gérer la révocation des jetons
L'un des défis inhérents aux JWT est qu'ils sont sans état. Une fois émis, un jeton valide reste valide jusqu'à son expiration, même si l'utilisateur se déconnecte ou change son mot de passe. Cela rend la révocation difficile.
Les temps TTL courts comme stratégie de révocation
Comme mentionné, la méthode la plus efficace pour gérer la révocation est de garder le temps d'expiration très court. Si un jeton est compromis, l'attaquant n'a qu'une durée limitée pour l'utiliser.
Listes noires
Pour les applications nécessitant une révocation immédiate, vous pouvez implémenter une liste noire avec état. Lorsqu'un utilisateur se déconnecte ou que sa session est invalidée, vous ajoutez l'ID du jeton (JTI) à une base de données ou un cache. Avant de valider un jeton, le serveur vérifie si le JTI est dans la liste noire. Cependant, cette approche nécessite de maintenir un état, ce qui contredit la nature sans état des JWT.
6. Validez les revendications du jeton
Lors de la réception d'un JWT, votre serveur doit effectuer une validation rigoureuse. AWS détaille l'importance de valider l'émetteur (iss), l'audience (aud) et l'expiration (exp).
- Émetteur : Assurez-vous que le jeton a été émis par votre application.
- Audience : Assurez-vous que le jeton est destiné à votre API.
- Expiration : Vérifiez toujours la revendication
exppour vous assurer que le jeton n'a pas expiré.
Échouer à valider ces revendications peut entraîner des contournements d'autorisation, où un utilisateur accède à des ressources auxquelles il n'a pas droit.
7. Considérez des alternatives comme PASETO
Bien que les JWT soient largement utilisés, ils ont une histoire de failles de sécurité. Par exemple, la vulnérabilité de l'algorithme "none" a permis aux attaquants de forger des jetons. HackerNoon discute de l'essor de PASETO (Platform for Authentication, Security, and Encryption of Tokens), un nouveau standard de jeton conçu pour répondre aux vulnérabilités des JWT. PASETO prend en charge à la fois les clés symétriques et asymétriques et est conçu pour être plus sûr par défaut. Bien que les JWT restent le standard, la compréhension d'alternatives comme PASETO est cruciale pour les architectes prenant des décisions à long terme.
Questions Fréquentes
Quelle est la différence entre HS256 et RS256 ?
HS256 (HMAC avec SHA-256) utilise une clé secrète partagée entre le client et le serveur. RS256 (RSA avec SHA-256) utilise une clé privée pour signer le jeton et une clé publique pour le vérifier. RS256 est généralement considéré comme plus sûr pour les systèmes distribués car la clé privée ne quitte jamais le serveur.
Puis-je révoquer un JWT immédiatement ?
Comme les JWT sont sans état, vous ne pouvez techniquement pas révoquer un JWT immédiatement sans maintenir une liste noire ou utiliser des temps d'expiration courts. La solution la plus pratique est d'utiliser des jetons d'accès à courte durée de vie.
LocalStorage est-il sûr pour les JWT ?
Non, LocalStorage est vulnérable aux attaques XSS. Si votre application est compromise, un attaquant peut lire le LocalStorage et voler le JWT. Les cookies HttpOnly sont le mécanisme de stockage recommandé pour la sécurité.
Conclusion
La sécurisation des JWT nécessite une approche multicouche. En utilisant HTTPS, en gérant les secrets en toute sécurité, en stockant les jetons dans des cookies HttpOnly, en implémentant des temps d'expiration courts et en validant rigoureusement les revendications, vous pouvez réduire considérablement le risque de vol et de mauvaise utilisation des jetons. Alors que le paysage de la sécurité web évolue, rester informé des meilleures pratiques et des alternatives comme PASETO est essentiel pour maintenir une posture de sécurité robuste.
Références
- JWT vs PASETO : Quel est le meilleur outil pour générer des jetons sécurisés ?
- How to Build a Secure Nest.js REST API Using JWT and MongoDB
- How to secure API Gateway HTTP endpoints with JWT authorizer
- Best of 2021 – How to Revoke JSON Web Tokens (JWTs)
- JSON Web tokens (JWT): how to use them safely
- How to Create a JWT Secret in Node.js (Best Practices + Examples)
- How to monitor, optimize, and secure Amazon Cognito machine-to-machine authorization