Siirry sisältöön

Webhook-allekirjoitusten todentaminen

Jokaisessa toimituksessa on FeitPay-Signature-otsake:

FeitPay-Signature: t=1760961600,v1=186aa47526353adc39a808f8e0bd84f501a5a6a1f483572b1f8a3eab3ed44cc8
  1. Lue pyynnön raaka runko täsmälleen sellaisena kuin se saapui (tavuina). Älä jäsennä ja sarjallista JSONia ensin uudelleen — mikä tahansa muutos välilyönneissä tai avainten järjestyksessä rikkoo allekirjoituksen.
  2. Jäsennä otsake: t on Unix-aikaleima; jokainen v1 on heksadesimaalinen allekirjoitus. Ohita tuntemattomat skeemat.
  3. Muodosta allekirjoitettu viesti: <t> + "." + <raaka runko>.
  4. Laske HMAC-SHA256(avain = koko salaisuus "whsec_…" UTF-8-muodossa, viesti) ja koodaa tulos heksadesimaaliksi.
  5. Vertaa jokaiseen v1-arvoon vakioaikaisella vertailulla. Mikä tahansa vastaavuus kelpaa (vaihdon aikana arvoja on useita).
  6. Hylkää, jos |nyt − t| on suurempi kuin toleranssisi (oletus 300 sekuntia) — tämä estää toistohyökkäykset.
  7. Vasta nyt jäsennä JSON ja käsittele tapahtuma ohittaen kaksoiskappaleet event_id:n perusteella.

Virallisten kirjastojen virhesyyt: malformed_header, no_signatures, signature_mismatch, timestamp_outside_tolerance, invalid_payload. Vastaa niihin kaikkiin 400.

import { createServer } from 'node:http';
import { verifyWebhook, WebhookVerificationError } from '@feitpay/webhooks';
const secrets = [process.env.FEITPAY_WEBHOOK_SECRET!]; // add the previous secret while rotating
createServer(async (req, res) => {
const chunks: Buffer[] = [];
for await (const chunk of req) chunks.push(chunk as Buffer);
const raw = Buffer.concat(chunks); // the RAW body
try {
const event = await verifyWebhook({ payload: raw, header: req.headers['feitpay-signature'] as string, secrets });
// dedupe on event.event_id, then handle it
res.writeHead(200).end();
} catch (err) {
const reason = err instanceof WebhookVerificationError ? err.reason : 'error';
res.writeHead(400, { 'Content-Type': 'application/json' }).end(JSON.stringify({ error: reason }));
}
}).listen(4400);

Next.js-reittikäsittelijöissä käytä await request.text() (ei request.json()) saadaksesi raa’an rungon. Synkroninen Node-versio on saatavilla paketista @feitpay/webhooks/node (verifyWebhookSync).

Repositoriossa on kaikille kielille yhteiset vektorit tiedostossa packages/test-fixtures/src/webhook-vectors.json — kelvolliset allekirjoitukset, vaihto kahdella allekirjoituksella, muokattu runko, väärä salaisuus, vanhentunut ja tuleva aikaleima sekä puuttuva ja virheellinen otsake. TypeScript-, Python- ja Go-kirjastot ajavat kaikki tapaukset CI:ssä. Jos kirjoitat oman todentajan, aja se samaa tiedostoa vasten.

Lähetä itsellesi allekirjoitettu testi

Osio nimeltä “Lähetä itsellesi allekirjoitettu testi”
  • Hallintapaneeli: Integrointi → Webhookit → Lähetä testitapahtuma, tai
  • POST /v1/webhook-endpoints/{id}/test, joka asettaa jonoon allekirjoitetun webhook.test-toimituksen.

Yksikkötesteissä voit luoda kelvollisia otsakkeita paikallisesti funktioilla generateTestHeader (TypeScript), generate_test_header (Python) tai webhook.GenerateTestHeader (Go).