Sécurité des JWT : vulnérabilités, attaques et bonnes pratiques
·Les JSON Web Tokens (JWT) se sont imposés comme le standard de fait de l’authentification sans état dans les applications web modernes. Leur souplesse produit toutefois des erreurs de configuration aux conséquences lourdes. Lorsqu’un pentesteur voit un JWT, il ne voit pas un identifiant de session : il voit une surface d’attaque cryptographique.
À retenir
- Un JWT est encodé, pas chiffré : chaque claim du payload est lisible par quiconque détient le token.
- L’algorithm confusion (RS256 vers HS256) et l’algorithme
nonerestent les défauts de signature à plus fort impact que nous trouvons dans les implémentations maison et les applications héritées. - Un secret HS256 est un mot de passe. Un token intercepté se casse hors ligne avec Hashcat, sans aucune interaction supplémentaire avec la cible.
- Les paramètres d’en-tête fournis par le client, comme
kidetjku, transforment la vérification de signature en surface d’injection. - Une signature valide ne dit rien de la validité des claims :
exp,issetauddoivent être contrôlés à chaque requête. - Gardez les access tokens en mémoire et les refresh tokens dans des cookies
HttpOnly,Secure,SameSite— jamais danslocalStorage.
Anatomie d’un JWT : header, payload et signature
Un JWT se compose de trois parties : un header, un payload et une signature, séparées par un point (.). Pour un pentesteur, un JWT intercepté ressemble d’abord à une longue chaîne de caractères apparemment aléatoires. Voici un exemple réel :
eyJraWQiOiI5MTM2ZGRiMy1jYjBhLTRhMTktYTA3ZS1lYWRmNWE0NGM4YjUiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTY0ODAzNzE2NCwibmFtZSI6IkNhcmxvcyBNb250b3lhIiwic3ViIjoiY2FybG9zIiwicm9sZSI6ImJsb2dfYXV0aG9yIiwiZW1haWwiOiJjYXJsb3NAY2FybG9zLW1vbnRveWEubmV0IiwiaWF0IjoxNTE2MjM5MDIyfQ.SYZBPIBg2CRjXAJ8vCER0LA_ENjII1JakvNQoP-Hw6GG1zfl4JyngsZReIfqRvIAEi5L4HV0q7_9qGhQZvy9ZdxEJbwTxRs_6Lb-fZTDpW6lKYNdMyjw45_alSCZ1fypsMWz_2mTpQzil0lOtps5Ei_z7mM7M8gCwe_AGpI53JxduQOaB5HkT5gVrv9cKu9CsW5MS6ZbqYXpGyOG5ehoxqm8DL5tFYaW3lB50ELxi0KsuTKEbD0t5BCl0aCR2MBJWAbN-xeLwEenaqBiwPVvKixYleeDQiBEIylFdNNIMviKRgXiYuAvMziVPbwSgkZVHeEdF5MQP1Oe2Spac-6IfA
Le header et le payload sont de simples objets JSON encodés en Base64Url. Ils sont encodés, pas chiffrés. Toute personne qui accède au token peut décoder et lire ces données.
Visualiser la structure d’un JWT
Un JWT — techniquement un JWS, c’est-à-dire un JSON Web Token « signé » — se compose de trois sections séparées par des points : Header.Payload.Signature.
{ "alg": "HS256", "typ": "JWT" }{ "sub": "andrej", "role": "hacker" }HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
"secret"
) = MmM0ZGMxM2Y1NWQ2YTY2YTELe header
Le header contient les métadonnées du token lui-même : principalement son type et l’algorithme cryptographique employé pour le protéger. Le décodage de la première partie du token ci-dessus donne :
{
"kid": "9136ddb3-cb0a-4a19-a07e-eadf5a44c8b5",
"alg": "RS256"
}
Le payload
Le payload contient les « claims », c’est-à-dire les assertions relatives à l’utilisateur. C’est la cible principale des manipulations pendant une mission. Le décodage de la section centrale de notre exemple donne :
{
"iss": "portswigger",
"exp": 1648037164,
"name": "Andrej Šebeň",
"sub": "andrej",
"role": "pentester",
"email": "andrej@haxoris.com",
"iat": 1516239022
}
La signature
Puisque le header et le payload se lisent et se modifient sans difficulté, la sécurité de tout mécanisme fondé sur les JWT repose entièrement sur la signature cryptographique.
Le serveur qui émet le token calcule une empreinte du header et du payload encodés en Base64Url, à l’aide d’une clé de signature secrète. Ce mécanisme garantit deux choses :
- Comme la signature est directement dérivée du reste du token, modifier un seul octet du header ou du payload produit une signature qui ne correspond plus.
- Sans connaître la clé de signature du serveur, il ne devrait pas être possible de générer la signature correcte d’un header ou d’un payload forgé.
Ce qu’un attaquant cherche dans un JWT
Les JWT étant lisibles par conception, les attaquants les traitent comme une source de reconnaissance, et non comme des données chiffrées. Du point de vue offensif, c’est dans le payload que se logent la plupart des failles logiques. Voici les claims que nous inspectons en premier :
| Claim | Rôle | Ce que nous vérifions |
|---|---|---|
iss (Issuer) | Identifie l’émetteur du token. | Le backend le valide-t-il réellement ? Un système qui accepte des tokens émis par un tiers non autorisé est exposé à une confusion d’émetteur. |
sub (Subject) | L’utilisateur ou l’entité représentée, souvent un identifiant. | Référence directe non sécurisée (IDOR). Pouvons-nous remplacer cette valeur par admin ou user_id=1 et contourner l’autorisation ? |
aud (Audience) | Identifie le destinataire attendu. | Un token émis pour un microservice peut-il être rejoué contre un autre microservice, bien plus privilégié ? |
exp (Expiration Time) | L’horodatage Unix d’expiration du token. | Le serveur l’applique-t-il vraiment ? Nous rencontrons régulièrement des API qui acceptent indéfiniment des tokens expirés. |
nbf (Not Before) | La date avant laquelle le token ne doit pas être accepté. | Très souvent absent de la logique de validation. |
iat (Issued At) | La date de création du token. | Utile pour calculer les durées de vie et repérer les tokens qui ne tournent jamais. |
Reconnaissance du payload : une mine d’informations
Le payload étant visible par quiconque détient le token, les équipes de développement devraient le considérer comme une information publique. Lors de nos missions, nous trouvons fréquemment des détails internes exposés inutilement par des claims personnalisés :
- Cartographie du réseau interne : des claims tels que
"node_ip": "10.0.4.12","cluster": "prod-eu-west-3a"ou"db_host": "internal-db.local"révèlent l’architecture interne et les plages d’adresses. - Fuites sur le socle technique : les conventions de nommage trahissent la pile utilisée. Des claims comme
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/namesignalent un backend Microsoft .NET / Entra ID, ce qui nous permet de cibler des vulnérabilités propres à cette pile. - Données à caractère personnel : exposition inutile d’adresses e-mail, de numéros de téléphone, de noms complets ou d’adresses postales. La confidentialité relève ici de l’article 32 du RGPD (sécurité du traitement) et du principe de minimisation ; un payload bavard crée un écart que la CNIL considère comme un défaut de sécurité, et non comme un détail d’implémentation.
- Énumération des tenants et des rôles : des claims comme
"tenant_id": "uuid","is_god_mode": falseou"permissions": ["read:profile"]exposent le schéma d’autorisation et nous donnent les noms exacts des paramètres à viser pour une élévation de privilèges.
Exemple de payload trop bavard, observé en conditions réelles :
{
"iss": "auth.internal-corp.local",
"sub": "usr_99812",
"email": "andrej@haxoris.com",
"role": "admin",
"internal_ip": "10.240.12.88",
"db_shard": "shard-04-eu",
"is_admin": true,
"exp": 1748037164
}
Bearer tokens et refresh tokens : architecture et stockage
Une implémentation JWT solide repose sur deux types de tokens : des access tokens (bearer tokens) de courte durée et des refresh tokens de longue durée. Un mauvais stockage de ces éléments est l’une des vulnérabilités que nous signalons le plus souvent.
Bearer tokens (access tokens)
- Les access tokens autorisent les appels d’API et sont volontairement de courte durée, généralement de 5 à 15 minutes.
- Conservez-les uniquement en mémoire applicative. Évitez
localStorageetsessionStorage: toute vulnérabilité XSS exploitée les expose à l’attaquant.
Refresh tokens
- Les refresh tokens servent uniquement à obtenir de nouveaux access tokens après expiration.
- Ils doivent être stockés dans des cookies
HttpOnly,Secure,SameSite, ce qui empêche leur lecture par JavaScript, réduit nettement le vol de token par XSS et contribue à limiter le CSRF.
Le playbook du pentesteur : les attaques courantes sur les JWT
Lors d’un test d’intrusion d’application web, nos équipes déroulent systématiquement les vecteurs suivants.
A. Défauts de vérification de la signature
Beaucoup de vulnérabilités JWT proviennent d’une vérification de signature défaillante, et non d’une cryptographie cassée. Historiquement, certaines bibliothèques acceptaient l’algorithme none, ce qui permettait de supprimer purement et simplement la signature tout en modifiant librement des claims comme le rôle de l’utilisateur. Toutes les bibliothèques modernes majeures rejettent none par défaut, mais le défaut ressurgit encore dans les applications héritées et les implémentations maison — il mérite donc un test dès que vous rencontrez une pile non standard.
Autre grand classique : l’algorithm confusion. C’est l’une des vulnérabilités JWT à plus fort impact, et elle mérite d’être comprise précisément.
- RS256 est un algorithme asymétrique. Le serveur signe les tokens avec sa clé privée et les vérifie avec la clé publique correspondante. Cette clé publique est souvent librement accessible, exposée par exemple via un point de terminaison
/.well-known/jwks.json. - HS256 est un algorithme symétrique. Le serveur utilise un secret partagé unique pour signer et pour vérifier.
L’attaque exploite ce qui se produit lorsqu’un serveur accepte les deux algorithmes sans figer explicitement celui qu’il attend :
- L’attaquant récupère la clé publique du serveur, souvent trivialement, depuis le point de terminaison JWKS.
- Il modifie le payload — par exemple en faisant passer
"role": "user"à"role": "admin". - Il remplace
"alg": "RS256"par"alg": "HS256"dans le header. - Il resigne l’ensemble du token modifié (header et payload) en utilisant la clé publique comme secret HS256.
- Le serveur reçoit le token, lit
alg: HS256et le vérifie avec la clé publique en guise de secret HMAC. La vérification réussit, et le token forgé est accepté.

La cause première n’est pas une cryptographie cassée : c’est le serveur qui fait aveuglément confiance au header alg fourni par le client pour décider comment vérifier le token. En temps normal, modifier alg invaliderait la signature, puisque celle-ci couvre à la fois le header et le payload. Mais l’attaquant resigne l’intégralité du token modifié : la nouvelle signature est parfaitement valide sous l’algorithme substitué.
Les bibliothèques récentes ont largement éliminé ces défauts, mais ils subsistent dans les applications héritées et les implémentations JWT écrites sur mesure.
B. Secrets de signature faibles
Une application qui utilise un algorithme symétrique comme HS256 n’est pas plus sûre que le secret servant à signer le token.
Pendant un test d’intrusion, un JWT intercepté s’attaque intégralement hors ligne, avec des outils comme Hashcat ou John the Ripper. Les secrets faibles — nom de l’entreprise, mots du dictionnaire, formules prévisibles — tombent souvent en quelques minutes, ce qui permet ensuite de forger des tokens valides pour n’importe quel utilisateur sans jamais réinteragir avec l’application cible.
C. Injection de paramètres d’en-tête
Le header d’un JWT peut contenir des paramètres optionnels comme kid (Key ID) et jku (JWK Set URL), qui aident le serveur à déterminer quelle clé utiliser lors de la vérification. Ces valeurs étant fournies par le client, leur faire confiance sans validation ouvre des vulnérabilités sérieuses.
Les vecteurs les plus courants sont :
- la manipulation du paramètre
jkupour pointer vers un point de terminaison JWKS contrôlé par l’attaquant ; - l’exploitation d’une traversée de répertoires via le paramètre
kidlorsque les clés sont chargées directement depuis le système de fichiers ; - l’abus d’une injection SQL lorsque la valeur de
kidest concaténée dans une requête de base de données.
Les bibliothèques JWT matures traitent correctement ces cas, mais une logique de vérification écrite sur mesure continue de produire des constats en audit.
D. Défauts de validation des claims
Une signature valide ne signifie pas automatiquement qu’un token est digne de confiance. Chaque claim pertinent pour la sécurité doit également être validé par l’application.
Lors de nos missions, nous rencontrons régulièrement des API qui :
- acceptent des tokens expirés en ignorant le claim
exp; - ne valident pas le destinataire attendu (
aud), ce qui autorise le rejeu d’un token d’un service à l’autre ; - font confiance à n’importe quelle valeur d’émetteur (
iss) ; - s’appuient uniquement sur des claims contrôlés par le client, comme
role,tenantoupermissions, sans contrôler l’autorisation côté serveur.
Ces failles logiques ont souvent un impact réel supérieur à celui des faiblesses cryptographiques, parce qu’elles permettent d’utiliser des tokens légitimes à des fins non prévues.
Les outils de test de sécurité des JWT
Décoder du Base64 et manipuler des signatures à la main n’est pas efficace. Les pentesteurs s’appuient sur des outils spécialisés pour automatiser ces attaques :
- JWTAuditor : une plateforme de test côté client, pensée pour les pentesteurs. Elle permet une inspection rapide, la détection automatisée de vulnérabilités (algorithme
none, injections d’en-tête) et du cassage hors ligne, sans exposer les tokens du client à la télémétrie d’un tiers. - Burp Suite (extension JWT Editor) : très utilisé en test dynamique pour manipuler les tokens à la volée pendant l’interception HTTP.
- JWT.io : maintenu par Auth0, c’est l’outil de référence pour décoder manuellement un token et vérifier rapidement sa structure et sa signature en phase de reconnaissance.
- JWTLens : une alternative légère et respectueuse de la confidentialité. L’outil décode et vérifie les tokens entièrement dans le navigateur via l’API Web Crypto native ; vos tokens et vos clés ne quittent donc jamais votre poste. Comme aucune requête réseau n’est émise pendant la vérification, c’est un bon choix pour valider des algorithmes et des signatures sans risque de fuite.
Bonnes pratiques défensives
Pour que vos tokens ne figurent pas dans les constats critiques de votre prochain rapport de pentest, appliquez les contrôles suivants :
- Figez les algorithmes attendus : ne laissez jamais le token entrant décider de la façon dont il sera vérifié. Configurez explicitement votre routine de validation pour un algorithme précis (par exemple
RS256) et rejetez l’algorithmenonesans condition. - Validez tous les claims : une signature valide prouve seulement l’absence d’altération, pas la validité du token pour l’utilisateur courant. Contrôlez explicitement
exp(expiration),iss(émetteur) etaud(destinataire) à chaque requête. - Traitez les secrets symétriques comme des mots de passe : si votre architecture impose une signature symétrique (
HS256), la clé secrète équivaut à un mot de passe d’administration. Retenez un secret d’au moins 256 bits d’entropie, issu d’un générateur cryptographiquement sûr, stocké dans des variables d’environnement ou un gestionnaire de secrets — jamais en dur dans le code source. L’ANSSI publie un guide de sélection d’algorithmes cryptographiques qui constitue une référence utile pour ces choix. - Rappelez-vous qu’encoder n’est pas chiffrer : ne placez jamais de données sensibles, de données à caractère personnel ni de mots de passe dans un payload JWT. Quiconque intercepte le token le décode instantanément.
- Isolez le stockage des tokens : ne stockez jamais un access token de courte durée dans
localStorageousessionStorage, où une seule vulnérabilité XSS suffit à l’exfiltrer. Gardez les access tokens strictement en mémoire côté client, et placez les refresh tokens de longue durée dans des cookiesHttpOnly,Secure,SameSite.
Durcissement avancé : le pattern phantom token
Dans les environnements les plus sensibles, la parade la plus efficace contre le vol côté client consiste à ne jamais exposer le JWT au frontend. Les architectures d’entreprise récentes implémentent souvent le pattern « phantom token » :
- Le serveur d’autorisation délivre à l’application cliente une chaîne de session opaque et aléatoire, à la place d’un JWT.
- Lorsque le client appelle l’API, il transmet cette chaîne opaque.
- La passerelle d’API intercepte la requête, valide le token opaque auprès du serveur d’authentification (ou du magasin de sessions) et l’échange contre un JWT signé et complet.
- La passerelle transmet ce JWT aux microservices internes.
Questions fréquentes sur la sécurité des JWT
01Un JWT est-il chiffré ?
Non. Le header et le payload d’un JWT signé standard (un JWS) sont seulement encodés en Base64Url, pas chiffrés. Toute personne qui détient le token peut décoder et lire chacun de ses claims. La signature protège l’intégrité, pas la confidentialité : aucune donnée sensible ni donnée à caractère personnel n’a sa place dans un payload JWT.
02Qu’est-ce que l’algorithm confusion sur un JWT ?
L’algorithm confusion survient lorsque le serveur laisse le header alg du token décider de la façon dont la signature est vérifiée. L’attaquant récupère la clé publique RSA du serveur, remplace RS256 par HS256 dans le header, modifie le payload et resigne l’ensemble du token en utilisant cette clé publique comme secret HMAC. Un serveur qui accepte les deux algorithmes valide la contrefaçon. La parade consiste à figer l’algorithme attendu côté serveur.
03Où stocker les access tokens et les refresh tokens dans un navigateur ?
Conservez les access tokens de courte durée uniquement en mémoire applicative. Stockez les refresh tokens de longue durée dans des cookies HttpOnly, Secure, SameSite, afin que JavaScript ne puisse pas les lire. Ne placez jamais l’un ou l’autre dans localStorage ou sessionStorage, où une seule vulnérabilité XSS suffit à les exfiltrer.
04Comment les attaquants cassent-ils un secret de signature HS256 ?
Un token HS256 intercepté s’attaque intégralement hors ligne, avec des outils comme Hashcat ou John the Ripper, sans aucune interaction supplémentaire avec l’application cible. Les secrets faibles — nom de l’entreprise, mots du dictionnaire, formules prévisibles — tombent souvent en quelques minutes, après quoi l’attaquant peut forger des tokens valides pour n’importe quel utilisateur. Un secret symétrique doit offrir au moins 256 bits d’entropie et provenir d’un générateur cryptographiquement sûr.
05Une signature valide suffit-elle à faire confiance à un JWT ?
Non. Une signature valide prouve seulement que le token n’a pas été altéré. L’application doit encore valider chaque claim pertinent pour la sécurité : exp pour l’expiration, iss pour l’émetteur, aud pour le destinataire attendu. Elle ne doit jamais s’appuyer sur des claims fournis par le client, comme role ou permissions, sans contrôler l’autorisation côté serveur.
Comment Haxoris peut vous aider
La sécurité des tokens est rarement mise en défaut par la cryptographie : elle l’est par la configuration. Nous vous aidons à trouver ces écarts avant un attaquant :
- Test d’intrusion des applications web et des API, avec une attention particulière portée aux parcours d’authentification et d’autorisation.
- Revue de la logique d’émission et de vérification des JWT, y compris la gestion des clés, le traitement du JWKS et la rotation — dans le cadre d’un audit de sécurité informatique ou d’un audit de code source.
- Évaluation hors ligne de la robustesse de vos secrets de signature symétriques.
- Revue de conception du stockage des tokens, des durées de session et de l’architecture des refresh tokens.
Nos tests applicatifs s’appuient sur le guide de test OWASP WSTG, dont les chapitres consacrés à la gestion des sessions couvrent directement les points décrits ici. Le contre-audit est inclus, sans surcoût, pour vérifier vos correctifs après remédiation. Tous nos tests d’intrusion sont réalisés sur mandat écrit, dans un périmètre défini contractuellement (articles 323-1 et suivants du code pénal). Dernière vérification : 11 septembre 2026.
Conclusion
Les JWT ne sont pas vulnérables par conception. Ils le deviennent dès qu’une application laisse le token décider de la manière dont il doit être validé, ou qu’elle confond signature valide et autorisation. Figez l’algorithme, validez chaque claim, traitez les secrets comme des mots de passe d’administration et gardez les tokens hors du stockage navigateur : la majorité des constats décrits dans cet article disparaîtront de votre prochain rapport de test d’intrusion.
Sources et lectures recommandées
Les méthodes et les détails techniques de cet article s’inspirent des ressources de sécurité suivantes :
- PortSwigger Web Security Academy. JWT Security Vulnerabilities. Une analyse détaillée des défauts de vérification de signature et des injections d’en-tête. portswigger.net/web-security/jwt
- InfoSec Writeups. JWT Pentesting: A Journey from Token to Takeover. Des cas pratiques d’exploitation de configurations de tokens. infosecwriteups.com
- Auth0 / JWT.io. Introduction to JSON Web Tokens. La documentation de référence sur la structure des tokens et la RFC 7519. jwt.io/introduction
- JWTAuditor. Security Testing Tool. Utilisé pour la manipulation de payloads et la détection automatisée de vulnérabilités. jwtauditor.com