1) Receive a webhook and record the ID in your database. If it's a duplicate, stop.
2) Ask Stripe for the event matching the ID they gave you. If they reject it, stop.
3) Process the event.
It requires a roundtrip, but it's the only sane way to validate that the event you got is real and that you haven't seen it before without trying to validate a signature (lots of other APIs make you do that, though)
At the very least they should only provide the event ID over webhook otherwise people will take the lazy route and trust trivially forgeable messages.
Well, as zrail said, you can trivially verify it by fetching the associated event from Stripe and ignoring the webhook body.
We've debated this ourselves, though. While you can theoretically get good security with a combination of SSL and a shared secret in the URL, it's a bit ungainly, and we should perhaps encourage the right thing more straightforwardly by dropping the body from the POST.
I did it the way zrail suggested but laziness typically wins especially if you aren't even aware of the reasons you might want to do it the way zrail suggested.
I'm for making the right way the only way (or at least the default way).
For Iron.io, all our requests are authenticated using an OAuth token. So only people that know your OAuth token (and thus could use our API anyways) can use your webhook endpoints.
But there are other ways, too. The most common I've seen is to provide an API endpoint to verify events with (Stripe does this). If you use HTTPS to receive the webhook, and verify it with a request over HTTPS to the API you expect it to be coming from, you're ensuring the request is authentic.
For some webhook styles, it doesn't actually matter. Some people use webhooks to just say "Something happened", without actually saying what. In this style, the API is still responsible for the data and authentication, the webhook just says "Hey, wake up, the API has something new for you."
* Concatenate timestamp and token values.
* Encode the resulting string with the HMAC algorithm (using your API Key as a key and SHA256 digest mode).
* Compare the resulting hexdigest to the signature.
* Optionally, you can check if the timestamp is not too far from the current time.
So, you essentially get 3 extra parameters from your webhook, `timestamp`, `token` and `signature`. Obviously, the API key is the shared secret here between your app and Mailgun.http://developers.grooveshark.com/docs/public_api/v3/
However it depends on a shared secret for generating/verifying signatures, and some companies (cough Stripe cough) have yet to implement that. As someone else has already mentioned, thankfully each webhook request from Stripe has an ID in it so you can query their API for verifying a webhook's authenticity.
Speaking of which, the right way to do this is to validate their SSL client certificate, but I doubt many places are easily setup to do that - in fact I would bet the sending endpoint doesn't even use a certificate most of the time.