I think the "securing webhooks" section is missing some critical tips that we've learned in production. 1) Resolve the DNS of the webhook URL, and compare all returned addresses from that resolution against an IP blacklist, which includes all RFC1918 addresses, EC2 instance metadata, and any other concerning addresses. 2) Even though it seems like you'd want to, do NOT blindly return an unexpected response to the per…
> IP blacklist Please stop trying to enumerate badness. This is and always will be incomplete. http://www.ranum.com/security/computer_security/editorials/d...
Webhooks do’s and dont’s: what we learned after integrating APIs
61–70 of 83 posts
Re: Webhooks do’s and dont’s: what we learned after integrating APIs
#62How do people in production handle the possibility that your service might miss a webhook notification? If you miss a notification you'll end up with stale data and you won't know it. Slack has a retry policy for a while but will then just give up. Another webhook provider I've looked at says nothing at all about this sort of thing. How do folks deal with this in production systems? Seems to me like the best way to a…
- Get a notification email everytime the callback fails. The email contains the same information the callback was supposed to deliver
- Retries. We retry for the next 24 hrs (max) with an interval of 5 mins or until the callback call succeeds (within those 24hrs). We created a sub-resource called `calls` (/callbacks/[id]/calls) that keep the status of the call we made. If it succeeds, the status changes to "SUCCESS", if it fails, it remains in "FAILED". If even after 24hrs the receiver system being down, and the call does not succeed, the developer can make a call to GET /callbacks/[id]/calls?status=FAILURE and receive all the failed calls. They can process the content and do a PUT /callbacks/[id]/calls?id=ID1&id=ID2&id=ID3... with body as `{ "status": "SUCCESS" }` to mark them as "SUCCESS".
The calls are saved for upto 7 days, so that the dev has enough time to fix their server issues, and get back all the lost callback calls. This solved much of the client issues.
* An added benefit of this came to the devs who could not get an inbound POST from us into their network due to firewall restrictions. The firewall restriction defeated the purpose of live callbacks, but with the `status` option, they only checked for new (`FAILED`) notifications once every 2 hrs or so , and mark the one processed with `SUCCESS`. This way, they only look for `FAILED` and process when they have one. Else, nothing to do.
[1] Whispir - https://www.whispir.com/ [2] https://whispir.github.io/api/#handling-callback-failures
Re: Webhooks do’s and dont’s: what we learned after integrating APIs
#63It would have been interesting to read about tests for web-hooks. How do you do integration testing for example?
* Receive the HTTP POST submission to my hook end-point.
* Save this data in a queue.
* Return to the hook-caller "200 OK - $ID".
This was better than trying to initiate a long-running job as a result of the hook, and meant that I could trigger "fake webhooks" just by adding data to the queue manually.
I'm sure there are other approaches, but this is a flexible one that also gave the benefit of being simple. (For the queue I just used Redis.)
Re: Webhooks do’s and dont’s: what we learned after integrating APIs
#64How do people in production handle the possibility that your service might miss a webhook notification? If you miss a notification you'll end up with stale data and you won't know it. Slack has a retry policy for a while but will then just give up. Another webhook provider I've looked at says nothing at all about this sort of thing. How do folks deal with this in production systems? Seems to me like the best way to a…
I would prefer to implement the sending of webhooks in bulk - if the consumer falls behind, they receive up to 100-1000 webhooks per request (depending on the size and complexity of each individual webhook - ids only is 1000, complex documents 100). This drastically cuts down on the number of concurrent requests to a single client when load is high, or the consumer broke down for a period of time. Unfortunately, deve…
Re: Webhooks do’s and dont’s: what we learned after integrating APIs
#65How do people in production handle the possibility that your service might miss a webhook notification? If you miss a notification you'll end up with stale data and you won't know it. Slack has a retry policy for a while but will then just give up. Another webhook provider I've looked at says nothing at all about this sort of thing. How do folks deal with this in production systems? Seems to me like the best way to a…
Maybe webhook providers could provide an endpoint where one could poll for events that failed to deliver.
a) The producer of the events has to store them in semi-permanent storage. I've been there and done that - failed webhooks result in a table of tens of millions of rows, even if the memory on each event is only 48 hours. It's astounding how many events fail to process. And I've been through extensive verification that there is truly no problem on our side - it's always the client who is wrong. Emails back and forth for weeks with the client screaming "it's your fault!" - only to finally receive an "oops, we found the problem on our end... sorry".
b) Frankly, if the consumer of the events fails on a single webhook more than 5 times in a 24 hour period, that event is a permanent loss. The reason it fails consistently is because that specific event is a permanent failure to process on the consumer's side. It is probably throwing a 500 Internal Server Error or similar - every single time. 0.001% of webhook consumers actually have emergency alerts when webhooks fail on their end, so the job will continue to throw a silent/unlogged/unnoticed/ignored error no matter how many times you retry. These are the same type of developers who will never poll your "failure queue", because they don't even understand that their consumer endpoint throws 500 Internal Server Errors on 10% of your requests. You're trying to provide a service to developers that live in a fantasy world where errors and exceptions never happen on their end.
It's a simple fact that developers who consume webhook requests are a disgrace. Chances are that if a request fails two times, it will never succeed. And yet the best APIs will try hundreds/thousands of times over a 24 hour period - simply to prove to that client that it is their fault that they are not processing webhooks properly. There is only so much a webhook producer can do. There is no magic we can do if the consumer is copy/pasting PHP snippets from Google or Stackoverflow.
Story time. The most memorable situation I can remember is a client who was experiencing 100% webhook consumer failure for more than three weeks. The emails from their team - and subsequent phone calls from their CTO - were absolutely stunning; it got to the point that we were hounding our own business people to drop them as a client, the verbal abuse was that bad. Turns out they had a bunch of PHP developers who were for the first time writing their consumer webhook endpoint in C for some reason. They were trying to parse the custom "id" field that they sent us as a string in a JSON field, as an integer. It was all because they sent us a string, and choked on trying to re-interpret it as an integer. It hurts to even think about that case.
tldr; Fuck webhook consumers. Incompetent developers who don't know how to handle errors that are 100% their fault.
Funny aside: the most amusing cases come from PHP and .NET developers who expose their internal server errors in production. When you can copy/paste the response they gave you on a webhook because they are calling an undefined function or method... pure bliss.
Re: Webhooks do’s and dont’s: what we learned after integrating APIs
#66Earlier quoted context omitted.
Stripe has an "events" API that can be polled to receive the same content that you would have received via Webhook [1]. (Disclaimer: I work there.) If you missed some Webhooks due to an application failure, it's possible to page through it and look for omissions. I've spoken to at least one person integrating who had this sort of setup running as a regular process to protect against the possibility of dropped Webhook…
Oh gosh, that is super neat! :) I never even thought of using it that way. I just use events to check that it is a valid Stripe event (Probably easier / better to set up the ELB to only listen to certain addresses)
EDIT: Not Fowler, but his site lol.
Re: Webhooks do’s and dont’s: what we learned after integrating APIs
#67This is going to sound bizarre, but why do webhooks and not just an AMQP queue? I get that receiving HTTP POSTs is easier, but it just seems better to setup a publisher/subscriber relationship. That way, if a subscriber goes down, they can always catch up. And publishers can allow messages to sit in the queue with a TTL and max_size. It seems like a win-win for everyone.
It's not AMQP (sadly) but something I've done previously is to have the actual webhook endpoint be as dumb as possible, doing nothing but accepting the payload (maybe with some very high level validation that the request was expected) and pushing it into a real queueing system. This means you can handle all sorts of failure modes, not just the backend going down, but also bugs in the consumer that would otherwise res…
Read the transaction ID from the request body, and store it (with a date/time) in a table. A periodic process later checks them, and uses the payment service's API to validate the payment is valid and take appropriate action.
Re: Webhooks do’s and dont’s: what we learned after integrating APIs
#68I think the "securing webhooks" section is missing some critical tips that we've learned in production. 1) Resolve the DNS of the webhook URL, and compare all returned addresses from that resolution against an IP blacklist, which includes all RFC1918 addresses, EC2 instance metadata, and any other concerning addresses. 2) Even though it seems like you'd want to, do NOT blindly return an unexpected response to the per…
> IP blacklist Please stop trying to enumerate badness. This is and always will be incomplete. http://www.ranum.com/security/computer_security/editorials/d...
Pretty much the only alternative I can think of is to query whois databases of RIRs, but you would need blacklisting there as well since they do include private IP spaces as well (ex. you would need to blacklist netname IETF-RESERVED-ADDRESS-BLOCK).
Similar problem exists with route advertisements from transit providers. They are not going to provide you a list of routes they advertise to you (since they don't get those from their customers usually), so your only option is to blacklist bogons yourself (unless you want to manually approve every single prefix out there as needed).
Re: Webhooks do’s and dont’s: what we learned after integrating APIs
#69How do people in production handle the possibility that your service might miss a webhook notification? If you miss a notification you'll end up with stale data and you won't know it. Slack has a retry policy for a while but will then just give up. Another webhook provider I've looked at says nothing at all about this sort of thing. How do folks deal with this in production systems? Seems to me like the best way to a…
Re: Webhooks do’s and dont’s: what we learned after integrating APIs
#70I think the "securing webhooks" section is missing some critical tips that we've learned in production. 1) Resolve the DNS of the webhook URL, and compare all returned addresses from that resolution against an IP blacklist, which includes all RFC1918 addresses, EC2 instance metadata, and any other concerning addresses. 2) Even though it seems like you'd want to, do NOT blindly return an unexpected response to the per…
Our eventual solution? AWS Lambda. We built a simple function that receives a payload with the HTTP request to be made and the Lambda function makes the request. It serves as a sandboxed micro-proxy for all of our untrusted external HTTP calls. We give that Lambda function permission to do nothing within the AWS account. We even went to far as to place the Lambda in a dedicated AWS account to further isolate it, which prevents an admin accidentally placing the Lambda within a sensitive VPC, for example.
We still examine endpoint URLs to insure they don't belong to the internal network, but I sleep much better knowing that if something slips through the Lambda function is isolated from our internal resources and there's not too much interesting to see / probe / find.