Stripe Webhook in Bubble - big vulnerability to all apps that use them

Not if a different token is used per endpoint.

root key are for the full app.
or you create a custom check using your own key, my post is to warn devs that create there apps on bubble to that they need to use custom way to protect there app.

Yeah, that seems pretty straightforward using a custom endpoint URL - perhaps in combination with the meta-data approach that @Jici mentioned.

Not to beat this issue to death, but I’m genuinely curious…

It seems a unique token could be enforced per endpoint with a simple check in the WF. And since data access is controlled via server-side app logic (which is under the Bubble developer’s control), it’s unclear why the security risk would be any greater than a similar approach in a non-Bubble “coded” app.

Obviously, using signatures would be ideal (so perhaps some enterprising Bubble developer will step up).

1 Like

FWIW, here’s what I decided to do for now…

  • Obfuscate - I created a randomly generated string for the endpoint (as mentioned by @matt_moo). Sure, it can be seen in the swagger.json file, but at least it’s not obvious that it has anything to do with Stripe.

  • Authenticate - I enabled Bubble authentication on the endpoint.

  • Verify Stripe IP Address - I make sure the source IP address belongs to Stripe - a measure Stripe recommends (in addition to signature verification). There are only a handful, so I just created an Option Set and use a contains operator against the appropriate request header field.

  • Verify Request Is Fresh - I check the signature timestamp and verify that the request was sent within the last 5 minutes.

This is all working fine, and while not bulletproof, I’m certainly not going to lose any sleep wondering if my endpoint is secure.

I might change any of this down the road if I feel it’s warranted.

It’s not obvious to me how one would go about signature verification in Bubble - even with a plugin. Any ideas, @Jici?

4 Likes

It’s absolutely possible and not different for Bubble than any other tools that receive a webhook from Stripe. And may already be possible using existing plugin. It’s may be just a little bit more complex because you will need more than 1 plugin to achieve this actually. But it’s absolutely possible to create a plugin that will do it for you.

Thanks for the reply, @Jici.
 
 

But HOW? I tried a couple approaches but couldn’t come up with a way to access the raw payload (request body).
 
 

The issue is not implementing the verification code, but rather how to get access to the raw payload - i.e. how to get the raw request data from a Bubble endpoint workflow into the context of a plugin.

Or are you saying there’s a way for a plugin itself to function as an endpoint? Maybe there’s something I’m missing.

It almost seems like something that Bubble would have to implement as an internal plugin; and if they did, I would recommend it be a separate plugin that implements an action. That way, it could be used with any Stripe plug-in.
 
 

Not that I can see.

1 Like

I cmpletely forget that for signature you need to compare the header content with the raw body.
I think, but I may be wrong that the process may look like this
A) Activate detect header data in endpoint
B) Create a request to the “events” endpoint" ( https://api.stripe.com/v1/events/[eventID]) Set this as a TEXT type, not json
C) In the endpoint you will need to use a plugin that let you decode the header. I think the best thing would be to create one that will process all the signature and comparison. Will have basically three fields: A) Webhook Endpoint Secret B) Body (from the endpoint created as TEXT) and C) Header (from the API request data). This plugin should return true if the signature is ok and false is not. I guess it would also be possible using an existing HMAC decoder plugin that already exist and just compare the result of this plugin with the Get Event Body from API Connector.

Not sure if this will work, but actually, this is something I think may work. If the event from webhook and the event from API are the same, there’s no reason that this will not work

1 Like

Exactly.

So you’re suggesting that a separate request be sent back to Stripe just to fetch what it has already delivered to the endpoint. I’m not sure if that would work either, but it would be interesting to try. (I’m not fond of the inefficiency of that approach though.)

Thanks for the suggestion.

EDIT

Now that I think about it, though, if the data is being pulled directly from Stripe via the API, it would seem to make signature verification pointless.

1 Like

Hello,

ty for the discussion, my post was intended also to create interest in finding alternatives.

That’s correct, but that will reduce the benefits on using webhooks.
You use extra resources your app, and your api usage on stripe get higher(100 read/100 write *s is the current limit)

Just a remainder:
if you retrieve a invoice, that for stripe is not just 1 api call, but 1 + every invoice item in the invoice.

I think that API usage shold not be w8st on invoice or subscription, but is better usage of them for Card information, payment session, all those thing that is super important to have the information immediately and not have save in your DB.

maybe this could work, i didn’t check, but having a better support from bubble directly with event managed as bubble event that’s what we should have, to build proper integration with stripe.

Just to remember that current issue with stripe and bubble is also multi item in stripe invoice or subscription that as not readable in bubble as independent object, so that i can save not just the invoice in my invoice db table but also the invoice item in my invoice item table.

in the end a better stripe event (aka webhooks) in Bubble is not needed just for security and create an optimized app, reduce the load on our side and stripe side. But also for providing better usability of those data.

Using the metod proposed by @Jici that call stripe to have the object directly, and ipotises that the object was a invoice with 3 item.
It will cost you 4 call and 7 read operation on stripe.
Call:

  • Retrieve invoice (4 read operation: 1 invoice, 3 item)

  • Retrieve invoice item (1 operation * 3 times)

1 Like

Yes, I would prefer proper sig verification when the endpoint is hit. I know exactly how I would build such a plug-in, so it’s a bit frustrating to not be able to access the delivered payload. :slightly_frowning_face:

2 Likes

@matt_moo
What do you mean by invoice item? Do you mean invoice line? If yes, there’s no reason to do 4 calls. Invoice endpoint already give you data for Invoice line. No need to do a call for each line

My last post was only related to validate the signature. 1 API Call. If you want to store the Invoice data too… 2 API Call. Don’t forget that the Rate limit 100/100 are /seconds!

And I agree that it would be a good thing if Bubble can have an option for Raw payload (Giving you both: raw and parsed)

What you call line are item → Stripe API Reference - Invoice Items

And bubble is not able to read those object independently or as an array of object.

So if you want to save them on your db you need to do a call for every record in that array.

that’s why I mailed bubble directly, but they just replay to check on the forum.
But clearly we can’t find a properer way by our own.

And better stripe event integration will reduce a lot of time consuming endpoint development and provide better security.

You cna save them as an object in DB. If you set the call as DATA, you can save it like you save a Bubble Data DB. You just need to select this as a field. And if you want to create one thing in your own DB for that, you can use a Backend WF to process the payload (previously store in your DB) for each line. No need to call API again.

For security, the “Signature” security purpose is not a really big thing. I mean that basically, the only thing that is important, is the endpoint Secret key. For the rest, it’s just more complex step for no reason. I think, but may be wrong, that if you are just able to decode the header with the secret key, you can consider this validate even if you don’t compare both payload. Why? Because I guess that if you are an hacker, and think that the server will validate signature, you will send also an header that will follow Stripe payload. So basically: the timestamp will be fine, The body will be the same. The only thing that is different is, the Secret key. If you can’t decode the header, this mean that this doesn’t come from Stripe but someone try to hack your endpoint. If your secret key get hacked/stolen, this mean that the signature verification will say it’s valid and you get hacked even if you use the signature validation process.

1 Like

You should never save bubble root API key on external services, and especially if is not encrypted as for webhooks url in stripe

Is not decoding, the stripe signature is a result of the entire call content combine with the secret key generated by stripe, similar to what you use on file with md5 signature to check integrity.
Just 1 bit of information will invalidate the signature and the event call (aka webhooks) should not be processed.

You can’t do a check on just the header.
And hack a SHA256 encoded signature is almost unhackable, you can search for 20 digit pass on SHA256 on google.
There is a reason behind the common standard in development and using cors + signature verification on webhooks is one of them, is super efficient to check the signature, is fast to generate the signature and is secure, no sorry super secure.

Using a standard API key is significantly less secure then use a signature, and you can’t compare what your propose as work around, in performance and efficiency and security with a simple web-hooks setup.

I know that bubble is a no-code platform, but if bubble team will provide us with the correct tools we can develop plugin that will make the app more secure and more optimized to process stripe event.

small information, we actually saturate the 100 sec request in read, for our main software some hour every 2 or 3 weeks, and we are a medium company, so is not something special what we ask, is just the basic on all platform.

@matt_moo
According from what I read from your previous post, there’s place to improvement in your process. If you are doing 4 calls for something that should take 1…

I’m not sure why you say ave Bubble root API when I’ve never mention this. I’m talking about the Secret key from Stripe for each webhooks endpoint. This is the key to encode/decode the signature. And sorry, I should ahve said that you need to encode and compare signature and not decode. My bad

I forget that, before Stripe introduce the signature, the real way to validate the data was to… call the API Back (You get the payload, but instead of working with it, you call the API Endpoint to get data from their API… this is a secure option too you can always do :P) But yes, This take one more call.