Security Tip: Validate Your Webhooks!

[Tip#51] Just because something isn't intended for users doesn't means someone won't find it, and if they know how to use it, you'd better have some protections in place!

Security Tip: Validate Your Webhooks!

Greetings friends! This week I want to remind you to always validate your webhook payloads! It’s a common weakness I often encounter, one that’s easily overlooked1, but it can have serious implications to your business.

For those heading to Laracon US, the schedule has just been announced. You’ll find my talk on the second day (Thurs 20th) at 1:30pm, just after lunch. It’s going to be such a fun talk, and don’t forget to bring your phone or laptop to take on my hacking challenge! If you’re unable to attend, the talk recordings should be online a few weeks after the conference. 🤞

⚠️ Thinking about a Laravel Security Audit and Penetration Test? I have limited spaces available in September & October, reach out now to book yours in! 🕵️

Please consider sharing Securing Laravel with your developer friends!

Validate Your Webhooks!

Webhooks a great: just create a route, wait for the provider to send through a useful payload, and then process it. What could possibly go wrong?

But… How do you know it’s the actual provider sending you the webhook? It’s not as if you’ve got your webhook endpoints in your user documentation, right? How is a hacker going to find your endpoints?

Now, who has webhooks that look like these:

/webhooks/<vendor>
/callbacks/<vendor>
/events/<vendor>
/api/webhooks/<vendor>
/api/callbacks/<vendor>
/api/events/<vendor>
/<vendor>/webhooks
/spark/webhook
...

I’m sure you get the point: webhook endpoints are very predictable and easy to find. This makes them incredibly easy to spoof, since it’s trivial for an attacker to learn the expected format of a webhook payload, forge their own, and send it to your app to be processed.

This is why webhook providers (usually) include some method of validating the payload. This is typically done through something like a HMAC2 signature with a pre-shared key. The provider builds the payload, generates a predictable signature (hash) using HMAC, and sends both the payload and signature through to you. Your app can then generate it’s own HMAC from the received payload, and verify the generated signature matches the provided one. If they don’t match, the payload has been tampered with/forged, and can be ignored.

The best place to start with validating your webhooks is to check the dev/API documentation for your provider. They should have a section on Webhook Security that outlines the process they require. Some may include it automatically in their SDKs too, which makes the job easier for you.

Here are a couple I recently came across:

If you can’t find their webhook security instructions, ask their support for help, and considering finding a new provider3.

If your provider doesn’t have a way to validate their webhooks…

  • They may provide IPs you can allow-list. While this is a relatively good security measure, IPs can still be spoofed with the right environment, so it shouldn’t be your only defence.

  • You could also add a random URL parameter4 you can confirm is present when receiving the webhook. This will prevent someone from guessing your endpoint, which is better than nothing, but anyone logging the requests will be able to see it.


Looking to learn more?
Security Tip #31: Canary Tokens
▶️ OWASP In Depth: A08:2021 – Software and Data Integrity Failures

  1. I think I say this a lot… but it’s true, there are lots of small weaknesses I keep seeing in the apps I audit.

  2. HMAC → Hash-based Message Authentication Code. We looked at these when we learned about Signed URLs.

  3. If they don’t care enough about security to provide a way to verify webhook payloads, you may find their security is lacking in other areas too…

  4. Something like a randomly generated 40-character string.