Come funzionano le firme dei webhook
Un webhook è solo un POST HTTP dal server di qualcun altro, e chiunque può fare un POST al tuo URL. Per provare che la richiesta viene dal provider, questo calcola un HMAC sul corpo con un segreto che conoscete solo voi due e lo invia in un header. Tu lo ricalcoli e confronti. Il segreto non viaggia mai; viaggia solo l’hash.
Perché compare «firma non valida»
- Hai calcolato l’hash del corpo analizzato, non dei byte grezzi. I framework che analizzano il JSON prima che il tuo handler giri (Express con
express.json(), Rails, Django) ti consegnano un oggetto; riserializzarlo cambia spazi e ordine delle chiavi e l’hash non corrisponde più. Cattura il corpo grezzo. - Segreto sbagliato. Stripe ha un
whsec_diverso per endpoint e per ambiente; il segreto di GitHub è per webhook; il signing secret di Slack non è il token del bot. - Il provider firma più del solo corpo. Stripe firma
timestamp.corpo; Slack firmav0:timestamp:corpo; Svix firmaid.timestamp.corpo; Twilio firma l’URL più i campi del form ordinati. La ricetta di ciascuno viene mostrata qui sopra quando lo scegli. - Codifica. Alcuni provider inviano hex, altri Base64; alcuni premettono
sha256=. Confronta le forme. - Proxy. Un proxy o una CDN che ricodifica il corpo (gzip, charset) o un limite di dimensione che lo tronca rompono l’hash.
Confrontare in sicurezza
In produzione, confronta con una funzione a tempo costante (crypto.timingSafeEqual, hmac.compare_digest, hash_equals) e controlla che il timestamp sia recente (Stripe e Slack ammettono cinque minuti) per fermare i replay. Questa pagina è un debugger, non un’implementazione di riferimento; usa un confronto ordinario perché gli attacchi temporali contro il tuo stesso browser non sono un problema.
Domande
Il mio segreto è al sicuro qui?
L’HMAC viene calcolato nel tuo browser con WebCrypto e la pagina non fa richieste di rete. Ciononostante, usa il segreto di un endpoint di test e ruota qualsiasi cosa incolli in una pagina web se vuoi essere rigoroso.
Perché GitHub invia sia X-Hub-Signature sia X-Hub-Signature-256?
Il primo è HMAC-SHA1, mantenuto per le vecchie integrazioni; il secondo è HMAC-SHA256 ed è quello da verificare. Entrambi sono calcolati sul corpo grezzo con lo stesso segreto.
Il valore atteso corrisponde tranne che per maiuscole/minuscole. È un fallimento?
L’hex non distingue maiuscole e minuscole nel codice di verifica di ogni provider, quindi no; anche questo strumento confronta l’hex senza distinzione. Il Base64 invece la distingue.
Stripe dice che il timestamp è troppo vecchio.
Le librerie di Stripe rifiutano le firme il cui t= dista più di 300 secondi dall’ora corrente, per prevenire i replay. Rigiocare una richiesta catturata più tardi fallirà per questo motivo anche se l’HMAC è corretto; lo strumento segnala l’età.