WebhookToolkit
Stripe · GitHub · Shopify · Slack

Walidator podpisu webhooka

Ostatnia aktualizacja: lipiec 2026

Twój dostawca wysyła nagłówek podpisu, Twój handler mówi, że się nie zgadza, a dokumentacja odpowiada SDK do zainstalowania. To nie mówi dlaczego. Wklej poniżej podpis, sekret i surowe body: przeliczamy HMAC w Twojej przeglądarce i przy niepowodzeniu sprawdzamy typowe przyczyny — zbędną spację w sekrecie, końcowy znak nowej linii, ponownie zserializowane body, przeterminowany timestamp.

W skrócie: podpis webhooka zawodzi prawie zawsze z jednego z pięciu powodów — zły sekret (test vs live), body ponownie zserializowane przez framework, timestamp poza oknem 5 minut, końcowy znak nowej linii lub pozostawiony prefiks sha256= / v0=. To narzędzie przelicza HMAC i mówi, który to.

Wklej niepasujący podpis

Wszystko działa w Twojej przeglądarce przez Web Crypto API. Twój sekret podpisu nigdy nie jest wysyłany na nasze serwery — sprawdź to w zakładce Sieć.

Cztery schematy podpisu

Wszystkie cztery to HMAC, ale różnią się tym, co jest hashowane i jak kodowany jest wynik. Jeden zły szczegół i każda dostawa zawodzi.

DostawcaCo jest podpisywaneAlgorytm
StripeHMAC z t.body; podpis i timestamp w jednym nagłówku Stripe-SignatureSHA-256 hex
GitHubHMAC surowego body; podpis w X-Hub-Signature-256SHA-256 hex
ShopifyHMAC surowego body; podpis w X-Shopify-Hmac-Sha256SHA-256 base64
SlackHMAC z v0:timestamp:body; potrzebny też nagłówek timestampSHA-256 hex

Twilio jest wyjątkiem — hashuje kanoniczny URL plus posortowane parametry, nie body. Do tego użyj walidatora podpisu Twilio.

Pięć prawdziwych przyczyn

Uszeregowane według częstości w wątkach supportu.

#PrzyczynaObjawRozwiązanie
1Zły sekretKażda dostawa zawodzi, nawet świeżaPomyłka test vs live — dostawcy wydają inny sekret podpisu na tryb i na endpoint.
2Ponownie zserializowane bodyZawodzi po sparsowaniu JSON przez frameworkPodpisuj surowe bajty, nie JSON.stringify(parsed): odstępy i kolejność kluczy zmieniają hash.
3Przeterminowany timestampDziała w testach, zawodzi przy ponownie wysłanych zdarzeniachStripe i Slack odrzucają starsze niż 5 minut. Nie wysyłaj ponownie zdarzenia sprzed godzin.
4Końcowy znak nowej liniiBody przesunięte o bajt, podpis nigdy dobryProxy lub edytor dodał znak nowej linii. Narzędzie wykrywa dokładnie ten przypadek.
5Prefiks porównany dosłowniesha256= lub v0= wliczone do porównaniaPorównuj tylko część hex/base64, nie prefiks schematu.

Pułapka surowego body

Przyczyna numer jeden: weryfikujesz wobec body sparsowanego-i-ponownie-zserializowanego zamiast dokładnych bajtów. JSON.stringify(JSON.parse(body)) zmienia odstępy i kolejność kluczy, więc HMAC już nie pasuje. Odczytaj surowe body, zanim cokolwiek je sparsuje.

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);
}

Zasada: przechwyć podpis i surowe bajty na wejściu, zweryfikuj, potem parsuj.

Timestampy i replay

Stripe i Slack wplatają timestamp w podpisywany ciąg i odrzucają wszystko starsze niż pięć minut — to ochrona przed replay, nie błąd. GitHub i Shopify nie, więc ważny podpis GitHub pozostaje ważny na zawsze. Jeśli narzędzie pokazuje ważny, ale wygasły, sekret i body są w porządku; po prostu wysyłasz ponownie stare zdarzenie. Wygeneruj świeżą dostawę zamiast wysyłać przechwyconą.

Gdy podpis się zgadza

Chcesz wysłać poprawnie podpisane zdarzenie testowe na własny endpoint? Signer webhooków tworzy je dla wszystkich sześciu dostawców. Aby przechwytywać i inspekcjonować prawdziwe dostawy, skieruj je na tunel Relay.

Otwórz signerTwilio signature validatorRelay

Najczęstsze pytania

Czy przechowujecie mój sekret podpisu?

Nie. HMAC liczony jest w Twojej przeglądarce przez Web Crypto; sekret i body nigdy nie trafiają na nasze serwery. Otwórz zakładkę Sieć: po kliknięciu Sprawdź nie wychodzi żadne żądanie.

Którzy dostawcy są obsługiwani?

Stripe, GitHub, Shopify i Slack — cztery schematy HMAC na body. Twilio podpisuje zamiast tego kanoniczny URL, więc ma własne narzędzie: walidator podpisu Twilio.

Tu przechodzi, ale mój serwer i tak odrzuca. Dlaczego?

Prawie zawsze body. Framework sparsował JSON, a Ty zserializowałeś je ponownie przed weryfikacją, co zmienia odstępy i kolejność kluczy. Podpisuj surowe bajty — zobacz snippety Express, Flask i Next powyżej.

Co znaczy „ważny, ale wygasły”?

HMAC jest poprawny, ale Stripe i Slack odrzucają też podpisy starsze niż pięć minut, by blokować replay. Jeśli przechwyciłeś zdarzenie i wysyłasz je później, weryfikacja zawodzi na timestampie, choć sekret jest dobry.

Walidator podpisu webhooka: Stripe, GitHub, Shopify, Slack · Webhook Toolkit