Generatore HMAC

Calcola HMAC-SHA-1, SHA-256, SHA-384 e SHA-512 da un messaggio e una chiave, e identifica da quale proviene una firma data.

Messaggio
HMAC-SHA-1
HMAC-SHA-256
HMAC-SHA-384
HMAC-SHA-512

Inserisci una chiave per calcolare le firme.

Che cosa fa questo strumento

HMAC trasforma un messaggio e un segreto condiviso in una firma breve. Chiunque possieda lo stesso segreto può ricalcolarla e vedere se il messaggio è arrivato immutato e se proviene da qualcuno che conosce anch’esso il segreto. Questo strumento calcola tutte e quattro le varianti comuni in una volta e, data una firma che ti è stata inviata, ti dice quale l’ha prodotta.

È di solito quel secondo verso il motivo per cui si arriva qui. Un webhook non supera la verifica, e la domanda vera non è «questa firma è valida» ma «quale delle diverse cose plausibili sto facendo diversamente dal mittente». Un prefisso in stile sha256= davanti a una firma incollata viene riconosciuto e rimosso, così il valore dell’intestazione può essere incollato esattamente com’è arrivato.

La chiave è dove le cose vanno storte

HMAC firma byte con byte. Il messaggio di solito è ovvio — il corpo grezzo della richiesta — ma la chiave quasi mai, perché un segreto arriva come stringa e una stringa non è byte finché non decidi come leggerla:

a3f2  ->  61 33 66 32   4 bytes   come testo
a3f2  ->  a3 f2         2 bytes   come hex

Entrambe le letture sono legittime, entrambe producono una firma perfettamente ben formata, e le due firme non hanno nulla in comune. Nulla ti avverte: nessun errore, nessuna lamentela sulla lunghezza, solo un valore che non coincide con quello calcolato dal mittente. Per questo qui la codifica della chiave è una scelta visibile e non un’ipotesi: quando una firma non coincide, è la prima cosa da ribaltare.

Come regola grossolana: un segreto con un prefisso tipo whsec_ o una sequenza di lettere maiuscole e minuscole e cifre di norma va inteso come testo; una stringa di esattamente 32 o 64 caratteri che usa solo 0-9 e a-f è di solito esadecimale; e una che finisce con = è quasi certamente Base64. Ma controlla la documentazione del mittente invece della forma, perché la forma non è una prova.

Il messaggio deve essere i byte esatti

L’altra metà di una mancata corrispondenza è il messaggio. HMAC è definito sui byte, quindi qualunque cosa cambi i byte cambia la firma per intero: non c’è punteggio parziale né quasi-centro.

  • Riserializzare il JSON. Analizzare un corpo e ricomporlo può riordinare le chiavi, cambiare gli spazi o normalizzare i numeri. Firma e verifica il corpo grezzo che hai ricevuto, mai una copia andata e tornata.
  • Un a capo finale. Alcuni strumenti lo aggiungono quando salvi il corpo su file; è un byte, e cambia tutto.
  • La codifica dei caratteri. Un corpo che contiene testo non ASCII va letto con la stessa codifica da entrambe le parti: in pratica UTF-8.
  • Compressione o middleware. Se qualcosa davanti al tuo handler decomprime o riscrive il corpo, verifica prima che accada, non dopo.

Molti provider inoltre non firmano il solo corpo. Stripe firma una marca temporale e il corpo uniti da un punto; AWS firma una richiesta canonica costruita da metodo, percorso, intestazioni e un hash del payload. Se la verifica fallisce contro il corpo semplice, la stringa firmata probabilmente non è il corpo semplice: è documentato dal lato del mittente e vale la pena leggerlo prima di continuare a indagare.

Perché SHA-1 è offerto qui e non nello strumento di hash

Lo strumento di hash segna SHA-1 come rotto. Questo elenca HMAC-SHA-1 senza avvisi, ed è deliberato, non una svista.

SHA-1 è inservibile per firme e certificati perché le collisioni si possono costruire: due documenti diversi si possono far condividere lo stesso digest. HMAC non dipende da quella proprietà. La sua sicurezza poggia sulla chiave segreta, e la costruzione — fare l’hash del messaggio due volte, con la chiave mescolata in entrambe — regge anche quando l’hash sottostante è debole alle collisioni. HMAC-SHA-1 resta solido ed è ciò che usano OAuth 1.0a e la vecchia firma AWS, perciò uno strumento che si rifiutasse di calcolarlo sarebbe semplicemente meno utile senza essere più sicuro.

Per qualcosa di nuovo, SHA-256 è la scelta sensata. Digest più lunghi non sono significativamente più forti qui — il tetto di sicurezza è la chiave, non la lunghezza del digest — quindi SHA-384 e SHA-512 valgono la pena solo quando qualcosa con cui devi interoperare li richiede.

Confrontare le firme in sicurezza

Questa pagina confronta con un normale confronto di stringhe, e qui va bene: la chiave ce l’hai tu, quindi non c’è nulla da far trapelare. In un server che verifica una richiesta in arrivo non va bene. Un confronto normale si ferma al primo byte diverso, quindi il tempo impiegato rivela quanta parte di un tentativo era corretta, e un attaccante che può inviare molte richieste può ricostruire una firma valida byte per byte.

Usa il confronto a tempo costante che la tua piattaforma offre — crypto.timingSafeEqual in Node, hmac.compare_digest in Python, hash_equals in PHP — sui byte grezzi e non su stringhe esadecimali. Insieme a questo: confronta con una firma che hai calcolato tu anziché fidarti di un algoritmo nominato nella richiesta, e rifiuta un messaggio la cui marca temporale è lontana da adesso, così una vecchia firma valida non può essere riutilizzata.

HMAC non è un hash né una firma

Qui si confondono tre cose, e la differenza conta per ciò che si può affermare dopo:

  • Un hash prende un messaggio e produce un digest. Chiunque può calcolarlo, quindi dimostra che il messaggio non è cambiato per sbaglio, non che venga da qualcuno in particolare.
  • Un HMAC prende un messaggio e un segreto condiviso. Entrambe le parti hanno la stessa chiave, quindi dimostra che il mittente conosceva il segreto. Non può dimostrare quale delle due abbia inviato, perché entrambe avrebbero potuto produrlo.
  • Una firma usa una chiave privata che solo il mittente possiede e una chiave pubblica con cui chiunque può verificare. È questo a dare il non ripudio: il mittente non può negarla in seguito.

HMAC è quindi lo strumento giusto fra due sistemi che già condividono un segreto — webhook, API interne, token di sessione — e quello sbagliato quando devi dimostrare a un terzo chi ha inviato qualcosa. Nota anche che autentica ma non nasconde: il messaggio viaggia in chiaro, e HMAC non dice nulla sulla riservatezza.

Verificare la firma di un webhook Stripe

Stripe è l’unica ricetta qui che non è un incollaggio, e di solito è quella che si è già provata prima di arrivare. L’intestazione Stripe-Signature è un elenco di elementi separati da virgole e non una firma, e la stringa che Stripe ha firmato non è il corpo della richiesta da solo. La documentazione di Stripe stessa spezza l’intestazione su più righe per leggibilità; una vera arriva su una sola riga.

Stripe-Signature:
t=1492774577,
v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd,
v0=6ffbb59b2300aae63f272406069a9788598b792a944a07aba816edb039989a39
  • Messaggio: il valore di t=, poi un punto, poi il corpo grezzo della richiesta esattamente come è arrivato. Per l’intestazione qui sopra quella stringa inizia con 1492774577. e il corpo segue subito. Stripe la chiama il payload firmato, ed è tutta la ragione per cui una firma Stripe non coincide mai con il solo corpo.
  • Chiave: il segreto di firma di quell’unico endpoint, intero, prefisso whsec_ compreso. Non è la tua chiave API, e non è il segreto di un altro endpoint: lo stesso URL registrato due volte ne ha due.
  • Codifica della chiave: Testo. Un segreto di firma è una stringa scelta da Stripe e, pur avendo l’aria casuale, non è né esadecimale né Base64; leggerlo come uno dei due dà byte diversi e una firma che non coincide con nulla.
  • Firma da verificare: il solo elemento v1, non l’intestazione intera. v1= si incolla così com’è, perché quell’etichetta viene rimossa esattamente come sha256= — l’intestazione completa invece no, perché il t= iniziale viene preso per l’etichetta e ciò che segue non è affatto una firma.

Altre tre cose su questa intestazione vale la pena saperle prima di indagare su qualunque altra. Ignora ogni schema che non sia v1: l’elemento v0 negli eventi di prova non è deliberatamente una firma vera, e ignorare il resto è proprio ciò che impedisce che ti venga imposto uno schema più debole. Mentre il segreto di un endpoint viene ruotato entrambi restano validi fino a un giorno e l’intestazione porta un elemento v1 per segreto, di cui uno solo coinciderà. E ogni tentativo di consegna viene firmato di nuovo, quindi un nuovo tentativo non porta la firma del primo: la marca temporale dentro la stringa firmata è anche ciò che rende il rifiuto di una firma vecchia una difesa vera e non un gesto, perché non può essere alterata senza rompere la firma.

Verificare la firma di un webhook GitHub

GitHub è l’incollaggio attorno al quale questo strumento è stato costruito, e l’unica ricetta qui che puoi controllare da un capo all’altro, perché GitHub pubblica un esempio svolto. La firma arriva in X-Hub-Signature-256 come l’etichetta sha256= seguita da un digest esadecimale, e quell’etichetta qui viene riconosciuta e rimossa, così il valore dell’intestazione entra esattamente come è arrivato.

X-Hub-Signature-256:
sha256=757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17
  • Messaggio: il corpo grezzo della richiesta, byte per byte. L’esempio pubblicato da GitHub firma il corpo Hello, World! e nulla dopo: nessun a capo finale.
  • Chiave: il segreto che hai digitato nelle impostazioni del webhook, esattamente come lo hai digitato. L’esempio pubblicato usa It's a Secret to Everybody.
  • Codifica della chiave: Testo. Un segreto di GitHub è una stringa che hai scelto tu, quindi non è mai esadecimale: anche un segreto composto solo da cifre esadecimali viene letto come i caratteri che hai digitato.
  • Firma da verificare: il valore dell’intestazione per intero, sha256= compreso. L’esadecimale viene confrontato senza distinzione fra maiuscole e minuscole, quindi non importa come lo stampino i tuoi log.

Quei tre valori insieme sono il controllo di sanità più rapido che esista: incollali e questa pagina segnala una corrispondenza su HMAC-SHA-256 in esadecimale, il che ti dice che sia il calcolatore sia la tua lettura della ricetta sono corretti prima di provare l’uno o l’altra su una consegna reale. GitHub invia anche un’intestazione più vecchia, X-Hub-Signature, che è HMAC-SHA-1 sullo stesso corpo e viene mantenuta solo per compatibilità con il passato; poiché questa pagina calcola tutti e quattro i digest in una volta, una firma proveniente da una qualsiasi delle due intestazioni viene identificata senza che tu debba dire da quale. L’unica cosa che non può salvare è un corpo arrivato come qualcosa di diverso dai byte inviati da GitHub: i payload possono contenere caratteri fuori da ASCII, ed entrambe le parti devono leggerli come UTF-8.

Verificare la firma di un webhook Shopify

Shopify scrive il suo digest in Base64 e non in esadecimale, e qui è l’unica differenza che conta: gli stessi 32 byte diventano 44 caratteri che finiscono con un solo segno di uguale, e quel carattere è riempimento e non un’etichetta, quindi non gli viene tagliato nulla davanti.

X-Shopify-Hmac-SHA256:
dXEH6g6yUJ/CESIczphLijdXC211hsIsRvQ3nIsEPhc=
  • Messaggio: il corpo grezzo della richiesta, byte per byte così come è stato consegnato. L’avviso di Shopify stessa riguarda il middleware che analizza il corpo: verifica prima e analizza dopo, perché un parser che ha già trasformato il corpo in un oggetto ha buttato via i byte.
  • Chiave: il segreto client dell’applicazione a cui appartiene il webhook. Non il suo token di accesso, e non la chiave API accanto nello stesso pannello.
  • Codifica della chiave: Testo. Come per gli altri due, il segreto è una stringa e non una codifica di byte.
  • Firma da verificare: il valore dell’intestazione per intero. Si incolla così com’è e, poiché contro ogni digest si provano sia esadecimale sia Base64, la codifica che questa pagina riporta è essa stessa la risposta a quale grafia abbia usato il mittente.

Il valore nel blocco qui sopra sta lì per mostrare la forma: sono gli stessi 32 byte dell’esempio GitHub, scritti in Base64 anziché in esadecimale. Vale la pena vederli affiancati, perché è tutto il contenuto della differenza fra le due intestazioni — un digest, due grafie — ed è il motivo per cui questa pagina nomina la codifica accanto all’algoritmo invece di dirti soltanto che qualcosa ha coinciso.

Domande frequenti

La mia firma non coincide. Che cosa controllo per primo?
La codifica della chiave, poi i byte del messaggio. Un segreto che sembra esadecimale spesso è inteso come esadecimale e non come testo, e i due producono firme completamente diverse senza alcun errore da nessuna delle due parti. Poi assicurati di firmare il corpo grezzo così come è arrivato e non una copia riserializzata.
Perché SHA-1 è offerto qui se lo strumento di hash lo dichiara rotto?
Perché HMAC non si basa sulla resistenza alle collisioni, la proprietà che SHA-1 ha perso. La sua sicurezza viene dalla chiave. HMAC-SHA-1 è ancora solido e in uso da OAuth 1.0a e dalla vecchia firma AWS, anche se SHA-256 è il valore predefinito giusto per qualcosa di nuovo.
Un digest più lungo è più sicuro?
Non in modo significativo. La forza di un HMAC è limitata dal segreto, non dalla lunghezza del digest, quindi SHA-512 non è quattro volte meglio di SHA-256. Scegli quello che si aspetta l’altra parte.
Che differenza c’è fra HMAC e una firma digitale?
HMAC usa un segreto che entrambe le parti conoscono, quindi dimostra che il mittente conosceva il segreto ma non quale parte abbia inviato. Una firma digitale usa una chiave privata che solo il mittente possiede, così un terzo può verificarla e il mittente non può negarla. Se ti serve quest’ultima proprietà, HMAC è lo strumento sbagliato.
Devo confrontare le firme con ===?
Non in un server. Un confronto normale ritorna appena i byte differiscono, e quel tempo rivela quanta parte di una firma indovinata era giusta. Usa il confronto a tempo costante della tua piattaforma sui byte grezzi. In questa pagina non ha importanza, perché la chiave ce l’hai già tu.
La mia chiave viene inviata da qualche parte?
No. Tutto viene calcolato nel tuo browser con la Web Crypto API; il messaggio e la chiave non lasciano mai il tuo dispositivo.
Come verifico la firma di un webhook Stripe?
Unisci tre cose in una sola stringa — la marca temporale dell’elemento t= dell’intestazione, un punto e il corpo grezzo della richiesta — e firmala con il segreto di firma dell’endpoint letto come testo, poi confronta il risultato con l’elemento v1 dell’intestazione. La sezione qui sopra la percorre campo per campo. Ciò che fa cadere quasi tutti è il primo passo: il corpo da solo non è ciò che Stripe ha firmato.
Come verifico la firma di un webhook GitHub?
Firma il corpo grezzo della richiesta con il segreto del webhook letto come testo, in SHA-256, e confronta il digest esadecimale con l’intestazione X-Hub-Signature-256. L’etichetta sha256= può restare quando la incolli qui. GitHub pubblica un esempio svolto — il corpo Hello, World! con il segreto It's a Secret to Everybody — ed è il modo più rapido di controllare la tua lettura della ricetta prima di provarla su una consegna reale.
Come verifico la firma di un webhook Shopify?
Firma il corpo grezzo della richiesta con il segreto client dell’applicazione a cui appartiene il webhook, letto come testo, in SHA-256, e confronta il digest Base64 con l’intestazione X-Shopify-Hmac-SHA256. Il valore dell’intestazione si incolla per intero così com’è: il segno di uguale finale è riempimento Base64. Quando non coincide, la causa solita è un middleware che ha analizzato il corpo prima che il tuo handler lo vedesse.
Come verifico la firma di un webhook di qualunque altro provider?
Lo risolvono quattro domande, e la documentazione del mittente le contiene tutte e quattro: quale intestazione porta la firma, quale stringa viene firmata davvero, come si suppone che vada letto il segreto, e se il digest è esadecimale o Base64. Riporta questo nei campi qui sopra. Se ancora non coincide, la risposta è quasi sempre la seconda: moltissimi mittenti firmano il corpo con qualcosa unito a esso anziché il corpo da solo.

Strumenti correlati