Lion Cipher Lab

Secure a webhook receiver with HMAC signatures (verify, constant-time, replay-proof)

Why it matters

A webhook is how one system tells another that something happened, in real time: Stripe POSTs your server when a payment succeeds, GitHub POSTs you when someone pushes, a messaging platform POSTs you when a message arrives. To receive them you publish a public URL — and that is the problem. A URL that accepts POSTed events, with no verification, is an unauthenticated command channel: anyone who discovers or guesses it can POST a forged 'payment.succeeded' and trick your app into shipping goods, crediting an account, or triggering a deploy. The fix the whole industry converged on is a message…

What you'll learn

Steps in this lab

  1. What a webhook is, and why a naive one is an open door
  2. Set up Python and Flask
  3. Build the NAIVE receiver and forge an event against it
  4. How GitHub and Stripe sign a webhook — the plan
  5. Build the HARDENED receiver: verify over the RAW body, before parsing
  6. Why constant-time: the timing side-channel that makes == unsafe
  7. The signer: how a real sender builds the request
  8. Attack it: forged, tampered, and replayed requests all get 401
  9. The judgment: HMAC vs the alternatives, and how the secret really fails

Open the full interactive lab →