Webhook Security: Verifying Signatures and Protecting the Receiver

A webhook is an HTTP callback: instead of your application repeatedly asking a service whether anything happened, the service posts to a URL you provide when something does. It replaces polling, it is the backbone of most SaaS integration, and it is an unauthenticated public endpoint accepting data that drives your business logic — which is why the security details matter.

Polling versus push

Polling wastes requests and adds latency: check every minute and you make 1,440 requests a day to learn about three events, each up to a minute late.

Webhooks invert this. The event arrives immediately and no request is wasted, at the cost of running a reachable endpoint and handling delivery reliability yourself — a webhook you were not listening for is simply missed unless the sender retries.

The receiver's problem

Your endpoint is on the public internet and anyone can post to it. Nothing about a request proves it came from the service it claims.

Signature verification is the answer, and it is not optional. The sender computes an HMAC over the request body using a shared secret and includes it in a header; the receiver recomputes it and compares. An attacker without the secret cannot produce a valid signature.

Three implementation details decide whether it works. Compute the HMAC over the raw body exactly as received — parsing and re-serializing JSON changes bytes and breaks the comparison, which is the most common integration bug. Use a constant-time comparison, since a byte-by-byte comparison that returns early leaks the signature through timing. And reject anything that fails rather than logging and continuing.

Replay protection comes next. A valid signed request captured once can be sent again, so senders include a timestamp in the signed payload — reject requests outside a short window, and record recently seen event identifiers to reject duplicates within it.

Verifying the source IP address is a weak supplement: it is spoofable for one-way traffic, provider ranges change, and it should never substitute for signature verification.

Handling the payload safely

A verified signature proves the sender, not that the content is sensible. Validate the payload against a schema, and treat every field as untrusted input — webhook data flowing into a database query or a template is the same injection problem as any other, as under SQL injection.

Respond quickly with a success status and process asynchronously via a queue. Senders time out, and a slow handler causes retries that duplicate work. Which means handlers must be idempotent: the same event delivered twice must produce one outcome, because at-least-once delivery is what every provider actually offers.

Rate limit the endpoint so a flood cannot exhaust your capacity, and be careful what the handler is allowed to do — an endpoint that triggers a disruptive action on receipt is a remote trigger for anyone who can get past the signature check, which is the reasoning behind the constraints under automation guardrails.

The sender's problem

If your application sends webhooks to customer-supplied URLs, you have built a request-forwarding service, and the risk is SSRF. A customer who registers a URL pointing at an internal address, or at the cloud metadata endpoint, makes your server fetch it.

Validate destinations: resolve the hostname, reject private and link-local address ranges, connect to the address you validated rather than re-resolving, and do not follow redirects. Send from a network segment with egress restricted so a bypass reaches nothing useful.

Also consider abuse: your infrastructure can be used to send traffic to a third party, so rate limit per customer and verify URL ownership before activating an endpoint.

Operational hygiene

Use HTTPS with certificate validation. Keep the signing secret out of source control, support rotation with an overlap period where both old and new signatures are accepted, and use a distinct secret per integration so one compromise is contained.

Make endpoint URLs unguessable, which reduces background noise without being a control. Log every received webhook with its verification result — a rising count of signature failures means either a rotation went wrong or someone is probing, and both are worth knowing about in your SIEM.

Exam angles

Know a webhook as an HTTP callback replacing polling, and the receiving endpoint as publicly reachable and therefore requiring authentication of the sender. Name HMAC signature verification over the raw body, using constant-time comparison, as the primary control, with timestamp-based replay protection alongside it. Know that handlers must be idempotent because delivery is at-least-once, and that accepting customer-supplied destination URLs creates SSRF exposure requiring destination validation and egress restriction.

Comments