Générateur HMAC

Calcule HMAC-SHA-1, SHA-256, SHA-384 et SHA-512 à partir d’un message et d’une clé, et identifie de laquelle provient une signature donnée.

Message
HMAC-SHA-1
HMAC-SHA-256
HMAC-SHA-384
HMAC-SHA-512

Saisissez une clé pour calculer les signatures.

Ce que fait cet outil

HMAC transforme un message et un secret partagé en une courte signature. Quiconque détient le même secret peut la recalculer et voir si le message est arrivé inchangé et s’il vient de quelqu’un qui connaît lui aussi le secret. Cet outil calcule les quatre variantes courantes d’un coup et, à partir d’une signature qu’on vous a envoyée, vous dit laquelle l’a produite.

Ce second sens est généralement la raison pour laquelle on arrive ici. Un webhook échoue à la vérification, et la vraie question n’est pas « cette signature est-elle valide » mais « laquelle des quelques choses plausibles est-ce que je fais autrement que l’expéditeur ». Un préfixe du type sha256= devant une signature collée est reconnu et retiré, si bien que la valeur d’en-tête peut être collée telle qu’elle est arrivée.

La clé est l’endroit où cela dérape

HMAC signe des octets avec des octets. Le message est en général évident — le corps brut de la requête — mais la clé presque jamais, car un secret arrive sous forme de chaîne et une chaîne n’est pas des octets tant que vous n’avez pas décidé comment la lire :

a3f2  ->  61 33 66 32   4 bytes   en texte
a3f2  ->  a3 f2         2 bytes   en hex

Les deux lectures sont légitimes, les deux produisent une signature parfaitement bien formée, et les deux signatures n’ont rien en commun. Rien ne vous prévient : pas d’erreur, pas de plainte sur la longueur, juste une valeur qui ne correspond pas à celle calculée par l’expéditeur. C’est pourquoi l’encodage de la clé est ici un choix visible plutôt qu’une supposition — quand une signature ne correspond pas, c’est la première chose à basculer.

À titre indicatif : un secret avec un préfixe du genre whsec_ ou une suite de lettres et de chiffres mêlant majuscules et minuscules se lit normalement en texte ; une chaîne de exactement 32 ou 64 caractères n’utilisant que 0-9 et a-f est généralement de l’hexadécimal ; et une chaîne finissant par = est presque certainement du Base64. Mais consultez la documentation de l’expéditeur plutôt que la forme, car la forme n’est pas une preuve.

Le message doit être les octets exacts

L’autre moitié d’une non-concordance, c’est le message. HMAC est défini sur des octets : tout ce qui change les octets change complètement la signature — pas de demi-point, pas de presque bon.

  • Re-sérialiser le JSON. Analyser un corps puis le re-générer peut réordonner les clés, changer les espaces ou normaliser les nombres. Signez et vérifiez le corps brut reçu, jamais une copie passée par un aller-retour.
  • Un saut de ligne final. Certains outils en ajoutent un lorsqu’on enregistre le corps dans un fichier ; c’est un octet, et cela change tout.
  • L’encodage des caractères. Un corps contenant du texte non ASCII doit être lu avec le même encodage des deux côtés — en pratique UTF-8.
  • Compression ou intergiciel. Si quelque chose devant votre gestionnaire décompresse ou réécrit le corps, vérifiez avant que cela n’arrive, pas après.

Beaucoup de fournisseurs ne signent d’ailleurs pas le seul corps. Stripe signe un horodatage et le corps joints par un point ; AWS signe une requête canonique construite à partir de la méthode, du chemin, des en-têtes et d’un hachage de la charge utile. Si la vérification échoue face au corps simple, la chaîne signée n’est probablement pas le corps simple — c’est documenté côté expéditeur et cela vaut la peine d’être lu avant de déboguer plus loin.

Pourquoi SHA-1 est proposé ici et pas dans l’outil de hachage

L’outil de hachage marque SHA-1 comme cassé. Celui-ci liste HMAC-SHA-1 sans avertissement, et c’est délibéré, non un oubli.

SHA-1 est inutilisable pour les signatures et les certificats parce qu’on peut construire des collisions : deux documents différents peuvent être amenés à partager une empreinte. HMAC ne dépend pas de cette propriété. Sa sécurité repose sur la clé secrète, et la construction — hacher le message deux fois, la clé étant mêlée aux deux passes — tient même quand le hachage sous-jacent est faible face aux collisions. HMAC-SHA-1 reste solide et c’est ce qu’emploient OAuth 1.0a et l’ancienne signature AWS ; un outil qui refuserait de le calculer serait donc simplement moins utile sans être plus sûr.

Pour toute nouveauté, SHA-256 est le choix raisonnable. Des empreintes plus longues ne sont pas significativement plus fortes ici — le plafond de sécurité est la clé, pas la longueur de l’empreinte — donc SHA-384 et SHA-512 ne valent d’être choisis que si quelque chose avec quoi vous devez interopérer les réclame.

Comparer les signatures sans danger

Cette page compare avec une comparaison de chaînes ordinaire, ce qui convient ici : vous détenez vous-même la clé, il n’y a donc rien à divulguer. Dans un serveur qui vérifie une requête entrante, cela ne convient pas. Une comparaison ordinaire s’arrête au premier octet différent : le temps qu’elle met révèle quelle part d’une supposition était correcte, et un attaquant capable d’envoyer beaucoup de requêtes peut retrouver une signature valide octet par octet.

Utilisez la comparaison à temps constant fournie par votre plateforme — crypto.timingSafeEqual en Node, hmac.compare_digest en Python, hash_equals en PHP — sur les octets bruts plutôt que sur des chaînes hexadécimales. À cela s’ajoute : comparez à une signature que vous avez calculée vous-même plutôt que de faire confiance à un algorithme nommé dans la requête, et rejetez un message dont l’horodatage est loin de maintenant, pour qu’une ancienne signature valide ne puisse pas être rejouée.

HMAC n’est ni un hachage ni une signature

Trois choses se confondent ici, et la différence compte pour ce que l’on peut affirmer ensuite :

  • Un hachage prend un message et produit une empreinte. N’importe qui peut la calculer : il prouve donc que le message n’a pas changé par accident, pas qu’il vienne de quelqu’un en particulier.
  • Un HMAC prend un message et un secret partagé. Les deux parties détiennent la même clé : il prouve donc que l’expéditeur connaissait le secret. Il ne peut pas prouver laquelle des deux a envoyé, puisque l’une comme l’autre aurait pu le produire.
  • Une signature utilise une clé privée que seul l’expéditeur détient, et une clé publique avec laquelle chacun peut vérifier. C’est ce qui donne la non-répudiation : l’expéditeur ne peut pas la nier ensuite.

HMAC est donc l’outil qu’il faut entre deux systèmes qui partagent déjà un secret — webhooks, API internes, jetons de session — et le mauvais outil quand il faut prouver à un tiers qui a envoyé quelque chose. Notez aussi qu’il authentifie mais ne dissimule pas : le message circule en clair, et HMAC ne dit rien de la confidentialité.

Vérifier la signature d’un webhook Stripe

Stripe est la seule recette ici qui ne soit pas un simple collage, et c’est en général celle que l’on a déjà essayée avant d’arriver. L’en-tête Stripe-Signature est une liste d’éléments séparés par des virgules et non une signature, et la chaîne que Stripe a signée n’est pas le corps de la requête à lui seul. La documentation de Stripe elle-même coupe l’en-tête en lignes pour la lisibilité ; un vrai en-tête arrive sur une seule ligne.

Stripe-Signature:
t=1492774577,
v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd,
v0=6ffbb59b2300aae63f272406069a9788598b792a944a07aba816edb039989a39
  • Message : la valeur de t=, puis un point, puis le corps brut de la requête exactement tel qu’il est arrivé. Pour l’en-tête ci-dessus, cette chaîne commence par 1492774577. et le corps suit immédiatement. Stripe l’appelle la charge signée, et c’est toute la raison pour laquelle une signature Stripe ne correspond jamais au corps seul.
  • Clé : le secret de signature de ce seul point de terminaison, en entier, préfixe whsec_ compris. Ce n’est pas votre clé d’API, ni le secret d’un autre point de terminaison — la même URL enregistrée deux fois en possède deux.
  • Encodage de la clé : Texte. Un secret de signature est une chaîne choisie par Stripe et, bien qu’il ait l’air aléatoire, ce n’est ni de l’hexadécimal ni du Base64 ; le lire comme l’un ou l’autre donne d’autres octets et une signature qui ne correspond à rien.
  • Signature à vérifier : le seul élément v1, pas l’en-tête entier. v1= se collant tel quel, puisque cette étiquette est retirée exactement comme sha256= — l’en-tête complet, lui, non, car le t= initial est pris pour l’étiquette et ce qui le suit n’est pas du tout une signature.

Trois autres choses méritent d’être connues sur cet en-tête avant de déboguer quoi que ce soit d’autre. Ignorez tout schéma autre que v1 : l’élément v0 des événements de test n’est délibérément pas une vraie signature, et ignorer le reste est précisément ce qui empêche qu’on vous impose un schéma plus faible. Pendant la rotation du secret d’un point de terminaison, les deux restent valides jusqu’à un jour et l’en-tête porte un élément v1 par secret, dont un seul correspondra. Et chaque tentative de livraison est signée à neuf : une nouvelle tentative ne porte donc pas la signature de la première — l’horodatage inscrit dans la chaîne signée est aussi ce qui fait du rejet d’une ancienne signature une vraie défense et non un geste, puisqu’il ne peut être modifié sans casser la signature.

Vérifier la signature d’un webhook GitHub

GitHub est le collage autour duquel cet outil a été construit, et la seule recette ici que vous puissiez vérifier de bout en bout, car GitHub publie un exemple entièrement calculé. La signature arrive dans X-Hub-Signature-256 sous la forme de l’étiquette sha256= suivie d’une empreinte hexadécimale, et cette étiquette est reconnue et retirée ici : la valeur d’en-tête entre donc exactement telle qu’elle est arrivée.

X-Hub-Signature-256:
sha256=757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17
  • Message : le corps brut de la requête, octet par octet. L’exemple publié par GitHub signe le corps Hello, World! et rien après — aucun saut de ligne final.
  • Clé : le secret que vous avez saisi dans les réglages du webhook, exactement tel que vous l’avez saisi. L’exemple publié utilise It's a Secret to Everybody.
  • Encodage de la clé : Texte. Un secret GitHub est une chaîne que vous avez choisie : ce n’est donc jamais de l’hexadécimal — même un secret composé uniquement de chiffres hexadécimaux est lu comme les caractères saisis.
  • Signature à vérifier : la valeur d’en-tête entière, sha256= compris. L’hexadécimal est comparé sans égard à la casse : peu importe donc comment vos journaux l’impriment.

Ces trois valeurs réunies sont la vérification de bon sens la plus rapide qui existe : collez-les et cette page annonce une correspondance sur HMAC-SHA-256 en hexadécimal, ce qui vous dit que la calculatrice et votre lecture de la recette sont l’une comme l’autre correctes avant d’essayer quoi que ce soit sur une livraison réelle. GitHub envoie aussi un en-tête plus ancien, X-Hub-Signature, qui est du HMAC-SHA-1 sur le même corps et n’est conservé que pour la compatibilité héritée ; comme cette page calcule les quatre empreintes d’un coup, une signature provenant de l’un ou l’autre en-tête est identifiée sans que vous ayez à dire lequel. La seule chose qu’elle ne peut pas sauver, c’est un corps arrivé autrement que sous la forme des octets envoyés par GitHub — les charges utiles peuvent porter des caractères hors ASCII, et les deux côtés doivent les lire en UTF-8.

Vérifier la signature d’un webhook Shopify

Shopify écrit son empreinte en Base64 et non en hexadécimal, et c’est la seule différence qui compte ici : les mêmes 32 octets deviennent 44 caractères se terminant par un unique signe égal, et ce caractère est du remplissage et non une étiquette — rien ne lui est donc retiré en tête.

X-Shopify-Hmac-SHA256:
dXEH6g6yUJ/CESIczphLijdXC211hsIsRvQ3nIsEPhc=
  • Message : le corps brut de la requête, octet par octet tel qu’il a été livré. L’avertissement de Shopify lui-même porte sur l’intergiciel qui analyse le corps — vérifiez d’abord et analysez ensuite, car un analyseur qui a déjà transformé le corps en objet a jeté les octets.
  • Clé : le secret client de l’application à laquelle appartient le webhook. Pas son jeton d’accès, et pas la clé d’API voisine dans le même panneau.
  • Encodage de la clé : Texte. Comme pour les deux autres, le secret est une chaîne et non un encodage d’octets.
  • Signature à vérifier : la valeur d’en-tête entière. Elle se colle telle quelle et, comme l’hexadécimal et le Base64 sont tous deux essayés face à chaque empreinte, l’encodage que cette page renvoie est lui-même la réponse à la question de la graphie employée par l’expéditeur.

La valeur du bloc ci-dessus est là pour montrer la forme : ce sont les mêmes 32 octets que dans l’exemple GitHub, écrits en Base64 au lieu de l’hexadécimal. Cela vaut la peine de les voir côte à côte, car c’est tout le contenu de la différence entre les deux en-têtes — une empreinte, deux graphies — et c’est pourquoi cette page nomme l’encodage à côté de l’algorithme au lieu de vous dire seulement que quelque chose a correspondu.

Questions fréquentes

Ma signature ne correspond pas. Que vérifier en premier ?
L’encodage de la clé, puis les octets du message. Un secret qui ressemble à de l’hexadécimal est souvent voulu comme tel et non comme du texte, et les deux produisent des signatures totalement différentes sans erreur ni d’un côté ni de l’autre. Ensuite, assurez-vous de signer le corps brut tel que reçu et non une copie re-sérialisée.
Pourquoi SHA-1 est-il proposé ici alors que l’outil de hachage le dit cassé ?
Parce que HMAC ne repose pas sur la résistance aux collisions, la propriété que SHA-1 a perdue. Sa sécurité vient de la clé. HMAC-SHA-1 reste solide et employé par OAuth 1.0a et l’ancienne signature AWS, même si SHA-256 est le bon choix par défaut pour toute nouveauté.
Une empreinte plus longue est-elle plus sûre ?
Pas de façon significative. La force d’un HMAC est bornée par le secret, pas par la longueur de l’empreinte : SHA-512 n’est donc pas quatre fois meilleur que SHA-256. Prenez celui qu’attend l’autre partie.
Quelle différence entre HMAC et une signature numérique ?
HMAC emploie un secret que les deux côtés connaissent : il prouve que l’expéditeur connaissait le secret, mais pas quel côté a envoyé. Une signature numérique emploie une clé privée que seul l’expéditeur détient, si bien qu’un tiers peut la vérifier et que l’expéditeur ne peut pas la nier. S’il vous faut cette dernière propriété, HMAC n’est pas le bon outil.
Dois-je comparer les signatures avec === ?
Pas dans un serveur. Une comparaison ordinaire revient dès que les octets diffèrent, et ce temps divulgue quelle part d’une signature devinée était juste. Utilisez la comparaison à temps constant de votre plateforme sur les octets bruts. Sur cette page cela n’a pas d’importance, puisque vous détenez déjà la clé.
Ma clé est-elle envoyée quelque part ?
Non. Tout est calculé dans votre navigateur avec l’API Web Crypto ; le message et la clé ne quittent jamais votre appareil.
Comment vérifier la signature d’un webhook Stripe ?
Réunissez trois choses en une seule chaîne — l’horodatage de l’élément t= de l’en-tête, un point, et le corps brut de la requête — puis signez-la avec le secret de signature du point de terminaison lu comme du texte, et comparez le résultat à l’élément v1 de l’en-tête. La section ci-dessus le déroule champ par champ. Ce qui piège la plupart des gens, c’est la première étape : le corps seul n’est pas ce que Stripe a signé.
Comment vérifier la signature d’un webhook GitHub ?
Signez le corps brut de la requête avec le secret du webhook lu comme du texte, en SHA-256, et comparez l’empreinte hexadécimale à l’en-tête X-Hub-Signature-256. L’étiquette sha256= peut rester quand vous la collez ici. GitHub publie un exemple entièrement calculé — le corps Hello, World! avec le secret It's a Secret to Everybody — et c’est le moyen le plus rapide de vérifier votre lecture de la recette avant de l’essayer sur une livraison réelle.
Comment vérifier la signature d’un webhook Shopify ?
Signez le corps brut de la requête avec le secret client de l’application à laquelle appartient le webhook, lu comme du texte, en SHA-256, et comparez l’empreinte Base64 à l’en-tête X-Shopify-Hmac-SHA256. La valeur d’en-tête entière se colle telle quelle — le signe égal final est du remplissage Base64. Quand cela ne correspond pas, la cause habituelle est un intergiciel qui a analysé le corps avant que votre gestionnaire ne le voie.
Comment vérifier la signature d’un webhook d’un autre fournisseur ?
Quatre questions le règlent, et la documentation de l’expéditeur les couvre toutes : quel en-tête porte la signature, quelle chaîne est réellement signée, comment le secret est censé être lu, et si l’empreinte est en hexadécimal ou en Base64. Reportez cela dans les champs ci-dessus. Si cela ne correspond toujours pas, la réponse est presque toujours la deuxième — énormément d’expéditeurs signent le corps avec quelque chose de joint à lui plutôt que le corps seul.

Outils connexes