Qui signe votre jeton : bien lire jku, kid, iss et aud
Le défi
L'API d'expédition de Caldera accepte des jetons signés par des transporteurs partenaires. Un jeton arrive, l'API a besoin de la clé publique qui va le vérifier, et la bibliothèque qu'elle utilise se veut serviable : plutôt que d'obliger l'équipe à maintenir une liste de clés partenaires, elle lit dans le jeton lui-même l'endroit où aller chercher la clé. C'est un vrai champ d'en-tête, il figure dans la spécification, et les bibliothèques l'honorent réellement. Trois noms d'hôte différents apparaissent dans ce jeton et ils sont tous plausibles. Un seul décide si la signature est digne de confiance, et c'est celui que l'attaquant choisit. Décodez le jeton et soumettez l'hôte auquel le vérificateur irait chercher la clé.
Ce que tu vas apprendre
- Distinguer les paramètres d'en-tête des claims du payload et savoir lesquels sont fiables
- Expliquer ce que signifie jku et dans quels cas une bibliothèque agit en fonction de ce champ
- Expliquer pourquoi iss ne peut pas servir à choisir une clé de vérification
- Décrire comment un attaquant forge une signature valide en fournissant lui-même la clé
- Repérer un nom d'hôte sosie qui se fait passer pour l'infrastructure d'un partenaire
Compétences testées
Prérequis
- Les trois segments d'un JWT
- Le fait que le base64url est un encodage, pas un chiffrement
Comment ça marche
Vérifier une signature revient à répondre à deux questions, pas une seule. La signature est-elle mathématiquement valide, et est-elle valide sous une clé à laquelle vous faites réellement confiance ? La plupart des bugs JWT se logent dans la seconde question, et celui-ci s'y loge entièrement.
Le jeton désigne trois hôtes. iss vaut https://auth.brightway.example, un claim d'identité dans le payload. aud vaut https://api.caldera.example, le destinataire prévu. Aucun des deux n'est une source de clé, et iss en particulier ne peut pas l'être : il se trouve dans le corps dont vous n'avez pas encore vérifié la signature, donc l'utiliser pour choisir la clé serait circulaire.
Le troisième est dans l'en-tête. jku signifie JWK Set URL et il est défini dans la RFC 7515. Il signifie : les clés qui vérifient ce jeton sont publiées ici. Une bibliothèque qui honore jku effectuera cette requête avant de valider quoi que ce soit, ce qui place jwks.brightway-cdn.example aux commandes de la confiance accordée à la signature.
Rien ne protège l'en-tête. C'est l'expéditeur qui l'écrit. Un attaquant génère donc une paire de clés, signe un jeton portant les claims de son choix, publie la clé publique correspondante sous forme de JWK Set sur un hôte qu'il contrôle, pointe jku dessus, et le vérificateur télécharge cette clé puis confirme la signature. Les mathématiques sont correctes de bout en bout. La clé était celle de l'attaquant.
kid est le champ où l'on s'attend à trouver ce genre de bug, et ce n'est pas lui ici : prod-2026-08 identifie une clé sans dire où elle vit. Le nom d'hôte sosie est la touche finale. À côté de auth.brightway.example, un hôte appelé brightway-cdn.example se lit comme le CDN de la même entreprise, alors que c'est un enregistrement totalement distinct.
Erreurs fréquentes
- Répondre auth.brightway.example.
issindique qui prétend avoir émis le jeton, et se trouve dans la partie que vous n'avez pas vérifiée. - Répondre api.caldera.example.
audest le destinataire, vérifié après la validation de la signature, jamais une source de clé. - Répondre prod-2026-08.
kidnomme une clé, ce n'est ni un hôte ni une URL. - Supposer que l'en-tête est protégé parce que le jeton est signé. La signature n'a de sens qu'une fois que vous disposez d'une clé de confiance, et c'est l'en-tête qui la choisit.
- Lire brightway-cdn.example comme brightway.example. Ce sont des enregistrements différents, ce qui est tout l'intérêt de ce nom.
Comment s'en protéger
Ne laissez jamais un jeton vous dire quelle clé le vérifie.
- Désactivez
jkuetx5udans le vérificateur. La plupart des bibliothèques ont un indicateur ou une liste blanche de paramètres d'en-tête autorisés. Si la vôtre les résout par défaut, c'est le réglage à changer dès aujourd'hui. - Figez la découverte des clés dans la configuration. Associez chaque émetteur à une URL JWKS que vous contrôlez, et n'allez chercher les clés que dans cette table.
- N'utilisez
kidque pour sélectionner parmi des clés que vous détenez déjà, jamais pour en récupérer une nouvelle, et rejetez toutkidinconnu. - Figez l'algorithme attendu par émetteur et rejetez tout le reste, pour qu'un jeton ne puisse pas vous faire basculer vers
noneou vers HMAC avec une clé publique utilisée comme secret. - Validez
issetaudaprès la signature, jamais avant, et déclenchez une alerte pour tout jeton dont l'en-tête porte ne serait-ce qu'un paramètre URL. Dans un déploiement sain, ce nombre est nul.