Guide complet sur les bonnes pratiques de sécurité des JWT : validation, stockage, algorithmes de signature et stratégies d'atténuation des vulnérabilités.
Jetons JWT : Bonnes pratiques de sécurité pour les applications mondiales
Les jetons web JSON (JWT) sont devenus une méthode standard pour représenter de manière sécurisée les revendications (claims) entre deux parties. Leur structure compacte, leur facilité d'utilisation et leur large prise en charge sur diverses plateformes en ont fait un choix populaire pour l'authentification et l'autorisation dans les applications web modernes, les API et les microservices. Cependant, leur adoption généralisée a également conduit à un examen plus approfondi et à la découverte de nombreuses vulnérabilités de sécurité. Ce guide complet explore les bonnes pratiques de sécurité des JWT pour garantir que vos applications mondiales restent sécurisées et résilientes face aux attaques potentielles.
Que sont les JWT et comment fonctionnent-ils ?
Un JWT est un jeton de sécurité basé sur JSON composé de trois parties :
- En-tête (Header) : Spécifie le type de jeton (JWT) et l'algorithme de signature utilisé (par ex., HMAC SHA256 ou RSA).
- Charge utile (Payload) : Contient les revendications (claims), qui sont des déclarations sur une entité (généralement l'utilisateur) et des métadonnées supplémentaires. Les revendications peuvent être enregistrées (par ex., émetteur, sujet, date d'expiration), publiques (définies par l'application) ou privées (revendications personnalisées).
- Signature : Créée en combinant l'en-tête encodé, la charge utile encodée, une clé secrète (pour les algorithmes HMAC) ou une clé privée (pour les algorithmes RSA/ECDSA), l'algorithme spécifié, et en signant le résultat.
Ces trois parties sont encodées en Base64 URL et concaténées avec des points (.
) pour former la chaîne JWT finale. Lorsqu'un utilisateur s'authentifie, le serveur génère un JWT, que le client stocke ensuite (généralement dans le stockage local ou un cookie) et inclut dans les requêtes ultérieures. Le serveur valide alors le JWT pour autoriser la requête.
Comprendre les vulnérabilités courantes des JWT
Avant de plonger dans les bonnes pratiques, il est crucial de comprendre les vulnérabilités courantes associées aux JWT :
- Confusion d'algorithme : Les attaquants exploitent la possibilité de changer le paramètre d'en-tête
alg
d'un algorithme asymétrique fort (comme RSA) à un algorithme symétrique faible (comme HMAC). Si le serveur utilise la clé publique comme clé secrète dans l'algorithme HMAC, les attaquants peuvent forger des JWT. - Exposition de la clé secrète : Si la clé secrète utilisée pour signer les JWT est compromise, les attaquants peuvent générer des JWT valides, usurpant l'identité de n'importe quel utilisateur. Cela peut se produire en raison de fuites de code, d'un stockage non sécurisé ou de vulnérabilités dans d'autres parties de l'application.
- Vol de jeton (XSS/CSRF) : Si les JWT sont stockés de manière non sécurisée, les attaquants peuvent les voler par des attaques de Cross-Site Scripting (XSS) ou de Cross-Site Request Forgery (CSRF).
- Attaques par rejeu (Replay Attacks) : Les attaquants peuvent réutiliser des JWT valides pour obtenir un accès non autorisé, surtout si les jetons ont une longue durée de vie et qu'aucune contre-mesure spécifique n'est mise en œuvre.
- Attaques par oracle de remplissage (Padding Oracle Attacks) : Lorsque les JWT sont chiffrés avec certains algorithmes et que le remplissage (padding) est mal géré, les attaquants peuvent potentiellement déchiffrer le JWT et accéder à son contenu.
- Problèmes de désynchronisation d'horloge (Clock Skew) : Dans les systèmes distribués, la désynchronisation des horloges entre différents serveurs peut entraîner des échecs de validation des JWT, en particulier avec les revendications d'expiration.
Bonnes pratiques de sécurité pour les JWT
Voici des bonnes pratiques de sécurité complètes pour atténuer les risques associés aux JWT :
1. Choisir le bon algorithme de signature
Le choix de l'algorithme de signature est critique. Voici ce qu'il faut considérer :
- Évitez
alg: none
: N'autorisez jamais que l'en-têtealg
soit défini surnone
. Cela désactive la vérification de la signature, permettant à quiconque de créer des JWT valides. De nombreuses bibliothèques ont été corrigées pour empêcher cela, mais assurez-vous que vos bibliothèques sont à jour. - Préférez les algorithmes asymétriques (RSA/ECDSA) : Utilisez les algorithmes RSA (RS256, RS384, RS512) ou ECDSA (ES256, ES384, ES512) chaque fois que possible. Les algorithmes asymétriques utilisent une clé privée pour la signature et une clé publique pour la vérification. Cela empêche les attaquants de forger des jetons même s'ils accèdent à la clé publique.
- Gérez les clés privées de manière sécurisée : Stockez les clés privées en toute sécurité, en utilisant des modules de sécurité matériels (HSM) ou des systèmes de gestion de clés sécurisés. Ne commettez jamais de clés privées dans les dépôts de code source.
- Effectuez une rotation régulière des clés : Mettez en œuvre une stratégie de rotation des clés pour changer régulièrement les clés de signature. Cela minimise l'impact si une clé est compromise. Envisagez d'utiliser les JSON Web Key Sets (JWKS) pour publier vos clés publiques.
Exemple : Utilisation de JWKS pour la rotation des clés
Un point de terminaison JWKS fournit un ensemble de clés publiques qui peuvent être utilisées pour vérifier les JWT. Le serveur peut effectuer une rotation des clés, et les clients peuvent mettre à jour automatiquement leur jeu de clés en interrogeant le point de terminaison JWKS.
/.well-known/jwks.json
:
{
"keys": [
{
"kty": "RSA",
"kid": "key1",
"alg": "RS256",
"n": "...",
"e": "AQAB"
},
{
"kty": "RSA",
"kid": "key2",
"alg": "RS256",
"n": "...",
"e": "AQAB"
}
]
}
2. Valider correctement les JWT
Une validation appropriée est essentielle pour prévenir les attaques :
- Vérifiez la signature : Vérifiez toujours la signature du JWT en utilisant la bonne clé et le bon algorithme. Assurez-vous que votre bibliothèque JWT est correctement configurée et à jour.
- Validez les revendications (claims) : Validez les revendications essentielles comme
exp
(date d'expiration),nbf
(pas avant),iss
(émetteur) etaud
(audience). - Vérifiez la revendication
exp
: Assurez-vous que le JWT n'a pas expiré. Mettez en œuvre une durée de vie raisonnable pour les jetons afin de minimiser la fenêtre d'opportunité pour les attaquants. - Vérifiez la revendication
nbf
: Assurez-vous que le JWT n'est pas utilisé avant sa date de début de validité. Cela empêche les attaques par rejeu avant que le jeton ne soit destiné à être utilisé. - Vérifiez la revendication
iss
: Vérifiez que le JWT a été émis par un émetteur de confiance. Cela empêche les attaquants d'utiliser des JWT émis par des parties non autorisées. - Vérifiez la revendication
aud
: Vérifiez que le JWT est destiné à votre application. Cela empêche que des JWT émis pour d'autres applications soient utilisés contre la vôtre. - Mettez en œuvre une liste de refus (Optionnel) : Pour les applications critiques, envisagez de mettre en œuvre une liste de refus (également connue sous le nom de liste de révocation) pour invalider les JWT compromis avant leur date d'expiration. Cela ajoute de la complexité mais peut améliorer considérablement la sécurité.
Exemple : Validation des revendications en code (Node.js avec jsonwebtoken
)
const jwt = require('jsonwebtoken');
try {
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'https://example.com',
audience: 'https://myapp.com'
});
console.log(decoded);
} catch (error) {
console.error('La validation du JWT a échoué :', error);
}
3. Stocker les JWT de manière sécurisée côté client
La manière dont les JWT sont stockés côté client a un impact significatif sur la sécurité :
- Évitez le stockage local (Local Storage) : Stocker les JWT dans le stockage local les rend vulnérables aux attaques XSS. Si un attaquant peut injecter du JavaScript dans votre application, il peut facilement voler le JWT du stockage local.
- Utilisez des cookies HTTP-Only : Stockez les JWT dans des cookies HTTP-Only avec les attributs
Secure
etSameSite
. Les cookies HTTP-Only ne sont pas accessibles par JavaScript, ce qui atténue les risques XSS. L'attributSecure
garantit que le cookie n'est transmis que via HTTPS. L'attributSameSite
aide à prévenir les attaques CSRF. - Envisagez les jetons de rafraîchissement (Refresh Tokens) : Mettez en œuvre un mécanisme de jeton de rafraîchissement. Des jetons d'accès à courte durée de vie sont utilisés pour l'autorisation immédiate, tandis que des jetons de rafraîchissement à longue durée de vie sont utilisés pour obtenir de nouveaux jetons d'accès. Stockez les jetons de rafraîchissement de manière sécurisée (par ex., dans une base de données avec chiffrement).
- Mettez en œuvre une protection CSRF : Lorsque vous utilisez des cookies, mettez en œuvre des mécanismes de protection CSRF, tels que les jetons synchroniseurs (synchronizer tokens) ou le modèle Double Submit Cookie.
Exemple : Définition de cookies HTTP-Only (Node.js avec Express)
app.get('/login', (req, res) => {
// ... logique d'authentification ...
const token = jwt.sign({ userId: user.id }, privateKey, { expiresIn: '15m' });
const refreshToken = jwt.sign({ userId: user.id }, refreshPrivateKey, { expiresIn: '7d' });
res.cookie('accessToken', token, {
httpOnly: true,
secure: true, // À définir sur true en production
sameSite: 'strict', // ou 'lax' selon vos besoins
maxAge: 15 * 60 * 1000 // 15 minutes
});
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: true, // À définir sur true en production
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 jours
});
res.send({ message: 'Connexion réussie' });
});
4. Se protéger contre les attaques par confusion d'algorithme
La confusion d'algorithme est une vulnérabilité critique. Voici comment la prévenir :
- Spécifiez explicitement les algorithmes autorisés : Lors de la vérification des JWT, spécifiez explicitement les algorithmes de signature autorisés. Ne vous fiez pas à la bibliothèque JWT pour déterminer automatiquement l'algorithme.
- Ne faites pas confiance à l'en-tête
alg
: Ne faites jamais aveuglément confiance à l'en-têtealg
dans le JWT. Validez-le toujours par rapport à une liste prédéfinie d'algorithmes autorisés. - Utilisez un typage statique fort (si possible) : Dans les langages qui prennent en charge le typage statique, appliquez une vérification de type stricte pour les paramètres de clé et d'algorithme.
Exemple : Prévention de la confusion d'algorithme (Node.js avec jsonwebtoken
)
const jwt = require('jsonwebtoken');
try {
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'] // Autoriser explicitement uniquement RS256
});
console.log(decoded);
} catch (error) {
console.error('La validation du JWT a échoué :', error);
}
5. Mettre en œuvre des mécanismes d'expiration et de rafraîchissement de jetons appropriés
La durée de vie des jetons est une considération de sécurité clé :
- Utilisez des jetons d'accès à courte durée de vie : Gardez les jetons d'accès avec une courte durée de vie (par ex., 5-30 minutes). Cela limite l'impact si un jeton est compromis.
- Mettez en œuvre des jetons de rafraîchissement : Utilisez des jetons de rafraîchissement pour obtenir de nouveaux jetons d'accès sans exiger que l'utilisateur se ré-authentifie. Les jetons de rafraîchissement peuvent avoir une durée de vie plus longue mais doivent être stockés de manière sécurisée.
- Mettez en œuvre la rotation des jetons de rafraîchissement : Effectuez une rotation des jetons de rafraîchissement chaque fois qu'un nouveau jeton d'accès est émis. Cela invalide l'ancien jeton de rafraîchissement, limitant les dommages potentiels si un jeton de rafraîchissement est compromis.
- Envisagez la gestion de session : Pour les applications sensibles, envisagez de mettre en œuvre une gestion de session côté serveur en plus des JWT. Cela vous permet de révoquer l'accès de manière plus granulaire.
6. Se protéger contre le vol de jetons
Prévenir le vol de jetons est crucial :
- Mettez en œuvre une politique de sécurité du contenu (CSP) stricte : Utilisez une CSP pour prévenir les attaques XSS. La CSP vous permet de spécifier quelles sources sont autorisées à charger des ressources (scripts, styles, images, etc.) sur votre site web.
- Nettoyez les entrées utilisateur : Nettoyez toutes les entrées utilisateur pour prévenir les attaques XSS. Utilisez une bibliothèque de nettoyage HTML de confiance pour échapper les caractères potentiellement malveillants.
- Utilisez HTTPS : Utilisez toujours HTTPS pour chiffrer la communication entre le client et le serveur. Cela empêche les attaquants d'écouter le trafic réseau et de voler les JWT.
- Mettez en œuvre HSTS (HTTP Strict Transport Security) : Utilisez HSTS pour indiquer aux navigateurs de toujours utiliser HTTPS lors de la communication avec votre site web.
7. Surveillance et journalisation
Une surveillance et une journalisation efficaces sont essentielles pour détecter et répondre aux incidents de sécurité :
- Journalisez l'émission et la validation des JWT : Journalisez tous les événements d'émission et de validation des JWT, y compris l'ID utilisateur, l'adresse IP et l'horodatage.
- Surveillez les activités suspectes : Surveillez les schémas inhabituels, tels que plusieurs tentatives de connexion infructueuses, des JWT utilisés depuis différents emplacements simultanément, ou des demandes de rafraîchissement de jeton rapides.
- Configurez des alertes : Configurez des alertes pour vous notifier des incidents de sécurité potentiels.
- Examinez régulièrement les journaux : Examinez régulièrement les journaux pour identifier et enquêter sur les activités suspectes.
8. Limitation du débit (Rate Limiting)
Mettez en œuvre une limitation du débit pour prévenir les attaques par force brute et les attaques par déni de service (DoS) :
- Limitez les tentatives de connexion : Limitez le nombre de tentatives de connexion infructueuses depuis une seule adresse IP ou un seul compte utilisateur.
- Limitez les demandes de rafraîchissement de jeton : Limitez le nombre de demandes de rafraîchissement de jeton depuis une seule adresse IP ou un seul compte utilisateur.
- Limitez les requêtes API : Limitez le nombre de requêtes API depuis une seule adresse IP ou un seul compte utilisateur.
9. Rester à jour
- Maintenez les bibliothèques à jour : Mettez régulièrement à jour vos bibliothèques JWT et dépendances pour corriger les vulnérabilités de sécurité.
- Suivez les bonnes pratiques de sécurité : Restez informé des dernières bonnes pratiques de sécurité et des vulnérabilités liées aux JWT.
- Effectuez des audits de sécurité : Effectuez régulièrement des audits de sécurité de votre application pour identifier et corriger les vulnérabilités potentielles.
Considérations mondiales pour la sécurité des JWT
Lors de la mise en œuvre de JWT pour des applications mondiales, tenez compte des éléments suivants :
- Fuseaux horaires : Assurez-vous que vos serveurs sont synchronisés sur une source de temps fiable (par ex., NTP) pour éviter les problèmes de désynchronisation d'horloge qui peuvent affecter la validation des JWT, en particulier les revendications
exp
etnbf
. Envisagez d'utiliser systématiquement des horodatages UTC. - Réglementations sur la protection des données : Soyez conscient des réglementations sur la protection des données, telles que le RGPD, le CCPA, et autres. Minimisez la quantité de données personnelles stockées dans les JWT et assurez la conformité avec les réglementations pertinentes. Chiffrez les revendications sensibles si nécessaire.
- Internationalisation (i18n) : Lors de l'affichage d'informations provenant des revendications JWT, assurez-vous que les données sont correctement localisées pour la langue et la région de l'utilisateur. Cela inclut le formatage approprié des dates, des nombres et des devises.
- Conformité légale : Soyez conscient de toute exigence légale relative au stockage et à la transmission de données dans différents pays. Assurez-vous que votre mise en œuvre de JWT est conforme à toutes les lois et réglementations applicables.
- Partage des ressources entre origines multiples (CORS) : Configurez correctement le CORS pour permettre à votre application d'accéder à des ressources depuis différents domaines. C'est particulièrement important lors de l'utilisation de JWT pour l'authentification entre différents services ou applications.
Conclusion
Les JWT offrent un moyen pratique et efficace de gérer l'authentification et l'autorisation, mais ils introduisent également des risques de sécurité potentiels. En suivant ces bonnes pratiques, vous pouvez réduire considérablement le risque de vulnérabilités et garantir la sécurité de vos applications mondiales. N'oubliez pas de rester informé des dernières menaces de sécurité et de mettre à jour votre mise en œuvre en conséquence. Donner la priorité à la sécurité tout au long du cycle de vie des JWT aidera à protéger vos utilisateurs et vos données contre les accès non autorisés.