WebhookToolkit
Stripe · GitHub · Shopify · Slack

Validatore di firma webhook

Ultimo aggiornamento: luglio 2026

Il tuo provider invia un header di firma, il tuo handler dice che non corrisponde, e la documentazione risponde con un SDK da installare. Non ti dice perché. Incolla firma, secret e body grezzo qui sotto: ricalcoliamo l'HMAC nel tuo browser e, se fallisce, riproviamo le mutazioni che di solito lo causano — uno spazio di troppo nel secret, un a capo finale, un body ri-serializzato, un timestamp scaduto.

In breve: una firma webhook fallisce quasi sempre per una di cinque ragioni — secret sbagliato (test vs live), un body ri-serializzato dal framework, un timestamp fuori dalla finestra di 5 minuti, un a capo finale o un prefisso sha256= / v0= rimasto. Questo strumento ricalcola l'HMAC e ti dice quale.

Incolla una firma che fallisce

Tutto gira nel tuo browser con la Web Crypto API. Il tuo secret di firma non viene mai inviato ai nostri server — verificalo nel tab Rete.

I quattro schemi di firma

Tutti e quattro sono HMAC, ma differiscono su cosa viene hashato e come si codifica il risultato. Un dettaglio sbagliato e ogni consegna fallisce.

ProviderCosa viene firmatoAlgoritmo
StripeHMAC di t.body; firma e timestamp in un unico header Stripe-SignatureSHA-256 hex
GitHubHMAC del body grezzo; firma in X-Hub-Signature-256SHA-256 hex
ShopifyHMAC del body grezzo; firma in X-Shopify-Hmac-Sha256SHA-256 base64
SlackHMAC di v0:timestamp:body; serve anche l'header timestampSHA-256 hex

Twilio è l'eccezione — hasha una URL canonica più parametri ordinati, non il body. Usa il validatore di firma Twilio per quello.

Le cinque cause reali

Ordinate per quanto spesso compaiono nei thread di supporto.

#CausaSintomoSoluzione
1Secret sbagliatoOgni consegna fallisce, anche una nuovaConfusione test vs live — ogni provider emette un secret di firma diverso per modalità e per endpoint.
2Body ri-serializzatoFallisce dopo che il framework ha parsato il JSONFirma i byte grezzi, non JSON.stringify(parsed): spaziatura e ordine delle chiavi cambiano l'hash.
3Timestamp scadutoPassa nei test, fallisce su eventi rinviatiStripe e Slack rifiutano oltre 5 minuti. Non rinviare un evento catturato ore dopo.
4A capo finaleBody sfasato di un byte, firma mai validaUn proxy o editor ha aggiunto un a capo. Lo strumento segnala questo caso esatto.
5Prefisso confrontato alla letterasha256= o v0= incluso nel confrontoConfronta solo la parte hex/base64, non il prefisso dello schema.

La trappola del body grezzo

La causa numero uno: verifichi contro il body parsato-poi-ri-serializzato invece dei byte esatti. JSON.stringify(JSON.parse(body)) cambia spaziatura e ordine delle chiavi, quindi l'HMAC non corrisponde più. Leggi il body grezzo prima che qualcosa lo parsi.

Express
// Express: keep the RAW bytes, do NOT let JSON re-serialise them
app.post('/webhook', express.raw({ type: '*/*' }), (req, res) => {
  const raw = req.body;                 // Buffer, exactly as received
  verify(raw, req.headers['stripe-signature'], secret);
});
Flask
# Flask: request.get_data() returns the raw body; request.json does NOT
raw = request.get_data()               # bytes, untouched
verify(raw, request.headers['X-Hub-Signature-256'], secret)
Next.js App Router
// Next.js App Router: read the text before parsing
export async function POST(req) {
  const raw = await req.text();         // sign THIS, not JSON.stringify(await req.json())
  verify(raw, req.headers.get('stripe-signature'), secret);
}

Regola pratica: cattura firma e byte grezzi al bordo, verifica, poi parsa.

Timestamp e replay

Stripe e Slack integrano un timestamp nella stringa firmata e rifiutano tutto ciò che supera cinque minuti — è protezione anti-replay, non un bug. GitHub e Shopify no, quindi una firma GitHub valida resta valida per sempre. Se lo strumento dice valida ma scaduta, secret e body sono a posto; stai solo rinviando un vecchio evento. Genera una consegna nuova invece di rinviarne una catturata.

Quando la firma è corretta

Devi inviare un evento di test firmato correttamente al tuo endpoint? Il signer di webhook ne costruisce uno per tutti e sei i provider. Per catturare e ispezionare consegne reali, puntale a un tunnel Relay.

Apri il signerTwilio signature validatorRelay

Domande frequenti

Salvate il mio secret di firma?

No. L'HMAC è calcolato nel tuo browser con Web Crypto; secret e body non raggiungono mai i nostri server. Apri il tab Rete: cliccando Verifica non parte alcuna richiesta.

Quali provider sono supportati?

Stripe, GitHub, Shopify e Slack — i quattro schemi HMAC sul body. Twilio firma invece una URL canonica, quindi ha uno strumento dedicato: il validatore di firma Twilio.

Passa qui ma il mio server la rifiuta comunque. Perché?

Quasi sempre il body. Il framework ha parsato il JSON e tu l'hai ri-serializzato prima di verificare, il che cambia spaziatura e ordine delle chiavi. Firma i byte grezzi — vedi gli snippet Express, Flask e Next sopra.

Cosa significa «valida ma scaduta»?

L'HMAC è corretto, ma Stripe e Slack rifiutano anche le firme di oltre cinque minuti per bloccare i replay. Se hai catturato un evento e lo rinvii dopo, la verifica fallisce sul timestamp anche se il secret è giusto.

Validatore di firma webhook: Stripe, GitHub, Shopify, Slack · Webhook Toolkit