JWS : signer et sécuriser vos échanges JSON
- Accueil
- Développement & chaîne logicielle
- JWS : signer et sécuriser vos échanges JSON
JWS : signer et sécuriser vos échanges JSON
Section intitulée « JWS : signer et sécuriser vos échanges JSON »JSON Web Signature (JWS), défini par la RFC 7515, signe une charge utile JSON (JavaScript Object Notation) afin de détecter toute modification et d’identifier le détenteur de la clé de signature. C’est le format courant des JSON Web Token (JWT) dans OpenID Connect et OAuth 2.0. Sa simplicité est trompeuse : un JWS correctement signé mais mal validé devient un laissez-passer parfaitement conforme.
Une signature numérique sur un message ressemble au sceau de cire des lettres d’autrefois : le contenu reste lisible par tous, mais le destinataire sait qui l’a scellé et voit tout de suite si quelqu’un a touché à la lettre en route. Cette page montre comment poser ce sceau et comment le vérifier.
→ Lire l’explication complète de la marmotte
Le compromis central est net : JWS facilite la vérification distribuée, car chaque service peut vérifier localement une signature avec une clé publique, mais cette autonomie reporte la sécurité sur la gouvernance des clés, la validation stricte des revendications et la durée de vie des jetons. Pour des jetons consommés par plusieurs services, une signature asymétrique est le choix par défaut. Une clé HMAC (Hash-based Message Authentication Code) partagée ne convient que si tous les vérificateurs sont explicitement autorisés à devenir émetteurs. C’est rarement le modèle voulu.
Format compact et garanties réellement fournies
Section intitulée « Format compact et garanties réellement fournies »Le format compact JWS contient trois segments Base64URL séparés par des points :
Base64URL(protected header).Base64URL(payload).Base64URL(signature)La signature porte exactement sur les deux premiers segments encodés, séparés par le caractère .. Elle ne porte pas sur le JSON reconstruit après décodage. Modifier des espaces, l’ordre de propriétés ou la représentation numérique après sérialisation change les octets signés. Un producteur doit donc sérialiser avant de signer, et un vérificateur doit toujours vérifier le message reçu, jamais une version JSON désérialisée puis réencodée.
L’en-tête protégé annonce notamment l’algorithme dans alg, par exemple RS256 pour RSA (Rivest-Shamir-Adleman) avec SHA-256 (Secure Hash Algorithm 256 bits), PS256 pour RSA-PSS (Probabilistic Signature Scheme), ou ES256 pour ECDSA (Elliptic Curve Digital Signature Algorithm) sur P-256. Il peut aussi contenir kid, l’identifiant de clé, destiné à sélectionner une clé dans un jeu de clés publié.
Le champ kid est un indice, pas une autorité. Il ne doit jamais déclencher une requête libre vers une URL construite depuis le jeton, ni sélectionner une clé dans un autre émetteur. Toute résolution de clé doit rester bornée à l’émetteur déjà approuvé et à son jeu de clés local ou mis en cache. Traiter kid comme un chemin de fichier, un nom DNS (Domain Name System) ou une URL ouvre des attaques de lecture locale, de Server-Side Request Forgery (SSRF) et de confusion de tenant.
Un JWS garantit l’intégrité des octets signés et la possession de la clé de signature. Il ne garantit ni la confidentialité, ni l’identité humaine, ni l’autorisation courante. Le contenu est simplement encodé, pas chiffré. Ne jamais placer un mot de passe, un secret d’API (Application Programming Interface) ou un attribut personnel inutile dans le payload. Le chiffrement d’un contenu demande JSON Web Encryption (JWE), avec ses propres clés et contraintes. Les frontières entre chiffrement et encodage sont détaillées dans cacher, coder et chiffrer.
Enfin, une signature ne crée pas de non-répudiation exploitable par magie. Avec une clé partagée, tous les détenteurs peuvent signer. Même avec une clé privée exclusive, l’attribution dépend de la protection de cette clé, des journaux et du contrôle d’accès au système de signature. Un JWS est une preuve cryptographique, pas une expertise juridique.
Choisir l’algorithme et distribuer les clés
Section intitulée « Choisir l’algorithme et distribuer les clés »none doit être refusé sans exception pour des jetons reçus d’un tiers. Le vérificateur doit disposer d’une liste d’algorithmes autorisés fixée par configuration, par émetteur et par usage. Il ne faut jamais accepter l’algorithme déclaré par l’en-tête comme une instruction. L’attaque classique de confusion algorithme consiste à présenter une clé publique RSA comme secret HMAC et à fabriquer un jeton HS256. Une bibliothèque permissive peut alors valider une signature calculée par l’attaquant.
Pour des échanges interservices ou des jetons d’identité, préférer PS256, ES256 ou EdDSA quand la pile JOSE (Javascript Object Signing and Encryption) le supporte de bout en bout. RS256 reste largement interopérable et raisonnable avec des clés RSA d’au moins 2048 bits, mais produit des signatures plus longues. ES256 réduit fortement la taille du jeton, au prix d’une attention stricte à la bibliothèque de signature et à la conversion du format ECDSA DER (Distinguished Encoding Rules) vers le format brut imposé par JWS. Une signature ECDSA aléatoire défectueuse peut révéler la clé privée. Il faut donc utiliser une bibliothèque maintenue qui génère le nonce de signature de façon sûre, idéalement déterministe selon RFC 6979.
HS256 ne doit pas servir à distribuer un jeton à plusieurs services indépendants. Chaque consommateur capable de vérifier possède alors le même secret et peut émettre n’importe quel jeton. Ce mécanisme est acceptable pour deux composants relevant du même domaine de confiance, avec un secret de haute entropie géré dans un coffre, une rotation coordonnée et aucun besoin de délégation. Dès qu’un vérificateur est moins digne de confiance que l’émetteur, passer à l’asymétrique.
Une clé privée de signature doit rester non exportable dans un module matériel de sécurité, Hardware Security Module (HSM), ou un service de gestion de clés dont le périmètre est équivalent. Le mécanisme PKCS#11 (Public-Key Cryptography Standards #11) doit autoriser la signature et interdire l’extraction de la clé privée. Un HSM ne répare toutefois ni un jeton trop long, ni une politique d’autorisation absente, ni une application compromise disposant du droit de signer.
La publication d’une clé publique via un JWKS (JSON Web Key Set) doit utiliser HTTPS (Hypertext Transfer Protocol Secure), une URL stable et une mise en cache bornée. Une rotation saine publie d’abord la nouvelle clé, commence ensuite à signer avec elle, puis retire l’ancienne seulement après expiration du dernier jeton qu’elle a signé, en ajoutant la marge des caches. Réutiliser le même kid pour une nouvelle clé rend les incidents de cache impossibles à diagnostiquer proprement.
Signer un JWS avec une clé RSA gardée dans un module matériel (PKCS#11)
Section intitulée « Signer un JWS avec une clé RSA gardée dans un module matériel (PKCS#11) »L’API PKCS#11 (Public-Key Cryptography Standards #11) permet de faire générer une clé RSA par un module cryptographique matériel, puis de lui faire signer la chaîne header.payload, étape clé dans la création d’un JSON Web Signature (JWS) avec RS256. L’application ne manipule jamais la clé privée, seulement des références vers elle :
Vérifier un JWS sans accepter un faux jeton
Section intitulée « Vérifier un JWS sans accepter un faux jeton »La vérification cryptographique est nécessaire, mais elle n’est qu’une étape. L’ordre compte : limiter d’abord la taille du jeton, décoder strictement Base64URL, contrôler la structure, sélectionner la politique attendue, vérifier la signature, puis valider les revendications. Lire le payload avant vérification peut servir à tracer un diagnostic, jamais à décider un accès.
Pour un JWT, contrôler au minimum iss (issuer, émetteur), aud (audience, destinataire), exp (expiration), nbf (not before, début de validité) et, selon le protocole, iat (issued at, date d’émission), jti (JWT ID) et nonce. Comparer iss comme une chaîne exacte configurée, sans normalisation opportuniste. aud doit contenir l’identifiant précis du service consommateur. Accepter toute audience ou seulement vérifier que le champ existe revient à accepter un badge destiné au bâtiment voisin.
La marge d’horloge doit rester faible et explicitement documentée, typiquement quelques dizaines de secondes. Une expiration longue compense une mauvaise disponibilité au prix d’une fenêtre de rejeu plus large. La révocation d’un certificat ou la suppression d’une clé du JWKS ne révoque pas les JWS déjà vérifiés ni les sessions déjà créées. Pour un droit sensible, choisir soit des jetons très courts, soit une vérification en ligne de l’état, soit une liste de révocation de jti. La signature seule ne fournit pas de révocation immédiate.
Exemple avec jose pour Node.js : l’algorithme attendu, l’émetteur et l’audience sont imposés côté vérificateur. Ils ne viennent pas du jeton.
import { createRemoteJWKSet, jwtVerify } from 'jose';
// URL configurée pour cet émetteur précis, jamais extraite de l'en-tête.const jwks = createRemoteJWKSet( new URL('https://identity.example.net/.well-known/jwks.json'));
const { payload, protectedHeader } = await jwtVerify(token, jwks, { algorithms: ['PS256'], // liste blanche, pas de négociation issuer: 'https://identity.example.net', // comparaison exacte audience: 'urn:service:facturation', clockTolerance: 30 // secondes, justification requise});
if (protectedHeader.typ !== 'at+jwt') { throw new Error('Type de jeton inattendu');}
// Décider ensuite selon des droits locaux, pas selon le seul champ "role".Le champ typ aide à séparer les profils de jetons, notamment at+jwt pour un jeton d’accès. Il ne remplace pas une politique de validation. Deux types de jetons signés par le même émetteur ne sont pas interchangeables : un jeton d’identité ne doit pas ouvrir une API parce que sa signature est correcte.
Les bibliothèques doivent être maintenues, configurées pour refuser les algorithmes non prévus et testées avec des jetons invalides. Les cas à couvrir incluent une signature tronquée, un en-tête dupliqué, un alg interdit, un kid inconnu, une clé de mauvaise courbe, une audience incorrecte, un jeton expiré et une clé retirée. La cryptanalyse ne sauve pas une validation qui ne teste que le happy path. Les principes de vérification sont liés à prouver qu’un message vient bien de son émetteur et à lire une garantie cryptographique sans la surinterpréter.
Exploitation : durée de vie, incidents et supervision
Section intitulée « Exploitation : durée de vie, incidents et supervision »Un service de signature doit être séparé des services qui consomment les jetons. Limiter les identités autorisées à invoquer l’opération de signature, imposer un format de claims et journaliser l’identifiant de clé, l’émetteur logique, le type de jeton et le résultat. Ne jamais journaliser le JWS complet : il circule souvent dans des en-têtes HTTP et peut contenir des données exploitables en clair.
La disponibilité du JWKS est un sujet d’architecture. Un vérificateur doit mettre les clés en cache et continuer à vérifier avec les clés déjà approuvées pendant une indisponibilité brève. Il ne doit pas accepter une nouvelle clé sans réussir à la récupérer depuis la source authentifiée. Un cache éternel bloque les rotations, un échec réseau qui désactive la vérification bloque l’accès, et un échec réseau qui accepte le jeton ouvre la porte. Ce dernier choix n’est jamais acceptable.
Superviser les refus par cause : signature invalide, clé inconnue, expiration, audience incorrecte, émetteur incorrect et échec de récupération du JWKS. Une hausse de kid inconnus peut signaler une rotation ratée, un mauvais tenant ou une tentative de contournement. Une hausse de jetons expirés révèle souvent un client bloqué, pas nécessairement une attaque, mais elle mérite une réponse avant que quelqu’un augmente exp à six mois par fatigue.
Les clés privées exigent sauvegarde et reprise. Avec un HSM, sauvegarder le domaine matériel, les objets de clé ou les mécanismes de restauration selon le modèle du fabricant, puis tester la restauration dans un environnement isolé. Perdre une clé active invalide les jetons émis et peut interrompre les intégrations. Conserver indéfiniment une clé compromise est pire : l’incident impose de désactiver la clé, publier une nouvelle clé, raccourcir ou invalider les sessions concernées et rechercher les signatures produites durant la période d’exposition.
JWS chiffre-t-il le payload ?
Section intitulée « JWS chiffre-t-il le payload ? »Non. Base64URL rend le contenu transportable, pas secret. Toute personne qui reçoit le jeton peut décoder son en-tête et son payload. Il faut minimiser les données embarquées ou utiliser un mécanisme de chiffrement adapté.
Peut-on accepter plusieurs algorithmes pour faciliter une migration ?
Section intitulée « Peut-on accepter plusieurs algorithmes pour faciliter une migration ? »Oui, mais seulement avec une politique explicite par émetteur et une date de retrait. Chaque algorithme accepté agrandit la surface d’attaque. Une migration sans échéance devient rapidement une compatibilité permanente.
Une signature valide suffit-elle pour autoriser une action ?
Section intitulée « Une signature valide suffit-elle pour autoriser une action ? »Non. Elle prouve que le jeton est intact et signé par une clé reconnue. L’application doit encore contrôler son émetteur, son destinataire, sa période de validité, son type et les droits applicables à la ressource demandée.
🐝 Ce qui arrive si on s’en passe
Section intitulée « 🐝 Ce qui arrive si on s’en passe »Un service qui accepte des jetons sans vérifier leur signature accepte aussi leurs modifications : il suffit de changer l’identifiant d’utilisateur dans la charge utile, de réencoder, et le serveur récepteur accorde l’accès au compte choisi par l’attaquant. Avec une clé secrète partagée, chaque service capable de vérifier est aussi capable de signer : la compromission du moins protégé d’entre eux permet de fabriquer des jetons valides pour tous les autres. Et comme le contenu n’est pas chiffré, un jeton intercepté livre au passage toutes les revendications qu’il transporte, y compris celles qu’on aurait préféré garder pour soi.
🦫 Explication de la marmotte 🍫
Section intitulée « 🦫 Explication de la marmotte 🍫 »Un message signé de cette façon se compose de trois morceaux mis bout à bout et séparés par des points. Le premier, l’en-tête, indique la méthode de signature employée. Le deuxième contient les données elles-mêmes, écrites dans un format texte courant sur le web, par exemple l’identifiant d’un utilisateur et la date d’émission. Le troisième est la signature. Chaque morceau est converti dans une forme de texte qui voyage sans problème dans une adresse ou un en-tête web.
Pour signer, le serveur émetteur prend l’en-tête et les données, puis calcule la signature. Avec une méthode asymétrique, il utilise une clé privée qu’il est seul à posséder, et les destinataires vérifient avec la clé publique correspondante. Avec une méthode à secret partagé, la même clé sert à signer et à vérifier. La clé privée peut rester enfermée dans un module matériel : l’application lui envoie les données, reçoit la signature, et ne voit jamais la clé.
Pour vérifier, le destinataire refait le calcul sur l’en-tête et les données reçus et le compare à la signature. Un seul caractère modifié suffit à faire échouer la comparaison, et le message est rejeté. Les données ne sont pas cachées : tout le monde peut les lire. Il faut donc protéger la clé privée, fixer une date d’expiration dans les données, et vérifier que la méthode annoncée dans l’en-tête est bien celle attendue, sinon un attaquant peut en imposer une autre.
À lire aussi
- Formats, bibliothèques et API : rendre la crypto utilisableDonner une structure web-first pour choisir des API sûres, concevoir des formats robustes et éviter les ambiguïtés de sérialisation.
- Sécuriser un contrat API-first dès la conceptionConcevoir un contrat d’API comme une frontière de confiance, avec authentification, autorisation, validation et exploitation sécurisées.
- Partage de données inter-organisations par APIPartager des données entre organisations exige des contrats exécutables, des API limitées et une confiance technique strictement bornée.
- Choisir ECDSA, EdDSA ou RSA pour un certificat TLSComparer les signatures à courbe elliptique ECDSA et EdDSA au RSA historique pour les certificats TLS, selon la taille de clé, la performance, la sécurité et la compatibilité.
Pages voisines
La citent
- Attributs du cookie de session
- Formats, bibliothèques et API : rendre la crypto utilisable
- Gouverner la cryptographie: inventaire, agilité et conformité
- Protéger une information en environnement hostile
- Transformer mots de passe et secrets applicatifs en clés
JWS : signer et sécuriser vos échanges JSON
Elle cite
- Lien dans les deux sens :JWE : chiffrer un jeton JSON sans se tromper
- Lien dans les deux sens :Prouver qu’un message vient du bon secret
- Frontières : cacher, coder, compresser et détruire
- Gérer la durée de vie des jetons OAuth
- Lire une garantie sans la surinterpréter
- OIDC, SAML et OAuth 2.1 en fédération
: les deux pages se citent l’une l’autre.
