En webhook er et HTTPS-endpoint hos modtageren, som afsenderen kalder med POST og noget JSON, når en hændelse indtræffer. Det er push i stedet for polling. I stedet for at din server spørger hvert femte sekund, om der er sket noget, får den besked, når der er.
Hvad der bliver sendt
I et verifikationsflow er hændelserne typisk de udfald, klienten ikke kan vente på synkront:
- Verifikation gennemført.
- Verifikation afvist.
- Session udløbet.
Brugeren kan lukke fanen, skifte til telefonen eller bruge tre minutter på at finde sin MitID-app frem. Derfor kommer svaret bagefter, ad en anden vej.
Hvorfor signaturen ikke kan springes over
Dit endpoint er offentligt. Det skal det være, ellers kunne afsenderen ikke nå det. Og det betyder, at alle andre også kan nå det.
Konsekvensen ved aldersverifikation er meget konkret. Uden signaturvalidering kan en hvilken som helst person sende et opdigtet kald til dit endpoint med indholdet "verifikation godkendt" og et ordrenummer, og din butik frigiver varen. Der har aldrig været et tjek. Der har aldrig været en MitID-app. Der var et POST-kald fra en terminal. Stripe skriver det samme om deres eget flow: uden validering kan en angriber sende falske hændelser og udløse handlinger som ordreafsendelse eller adgang til en konto.
Sådan ser valideringen ud
Stripe signerer med HMAC-SHA256 og lægger resultatet i headeren Stripe-Signature på formen t=<tidsstempel>,v1=<signatur>. Modtageren gør tre ting:
- Læser tidsstemplet og signaturen ud af headeren.
- Regner selv HMAC-SHA256 over tidsstemplet og den rå body med den delte hemmelighed og sammenligner med
v1. - Afviser kaldet, hvis tidsstemplet ligger uden for en tolerance.
Tidsstemplet er en del af det signerede, og derfor kan det ikke laves om. Det er beskyttelsen mod replay, hvor et gyldigt kald bliver opsnappet og sendt igen bagefter.
To detaljer bliver ofte tabt. Du skal signere over den rå body, ikke over det JSON, dit framework lige har parset og serialiseret om. Og du skal sammenligne strengene i konstant tid.
Efter valideringen
At kaldet er ægte, betyder ikke, at det er nyt. Nogle afsendere leverer den samme hændelse to gange. Gem hændelsens id, og gør intet, hvis du har set det før.
Det gælder også i den anden retning. Skal en webhook udløse et KYC-forløb eller frigive en konto, er det den slags handlinger, der er svære at rulle tilbage bagefter.