Reputation: 3094
My backend code usually wraps the client calls and exposes them via an endpoint like this:
import stripe
stripe.key = "API_KEY"
def wrap_create_customer():
return stripe.create_customer()
Clearly, it's possible to just reverse engineer my backend API and start calling it to read customer data, process charges etc. Effectively, Stripe API is exposed via my backend, since the Frontend-Backend connection is public. (Just like all backend starter codes in Stripe tutorials).
My frontend is a public, static site. It is not authenticated with the backend. To prevent requests from foreign origin, I am requiring the origin of the request to belong to my web domain.
Q: But if that's the fix, it would imply that validating the origin would be a sufficient condition to identify the real owner of the request. Then why doesn't Stripe let us move our code fully client side?
The only reason for requiring the Stripe Secret key is to authenticate requests. Why not just add allowed origins somewhere in the Stripe dashboard instead of requiring the key?
Q2: Is the whole reason behind backend code, to simply hide the Stripe Live key from public? Even if the backend can be accessed via 'non-secure' endpoints?
Q3: What steps should I undertake to have a secure client <-> backend integration, so that my backend is guaranteed to know that the request was indeed made by the client. (Client is a front-end application).
Upvotes: 2
Views: 1423
Reputation: 7459
In order to prevent fraud/abuse (such as Card Testing) of your Stripe account by malicious users, you'll want to protect some of your Stripe-powered endpoints. Stripe does recommend several mitigations, including user authentication, rate limits & captchas. Depending on your application & business, you might need a combination of several of these.
Note that user authentication can be added to static sites using a variety of self-hosted or third-party powered tools. GatsbyJS has a some pretty good documentation of this with multiple examples. Pretty much any pure client technique can be spoofed (such as origin, referrer etc), so those alone would not be sufficient to protect your backend server.
Upvotes: 1
Reputation: 17407
Typically, (I've never worked with stripe in particular, but with other similar providers) this works as follows:
The frontend includes an SDK which is initialized with a vendorId
and maybe some productIds
. There's nothing secret about this information. Because even if anybody else knows them, the only thing he can do with it is to buy items from your stripe account.
When a checkout is to be made, the client sends a checkout/{venderId}/{productId}
request to the payment provider. Some providers only provide "checkout links", where the customers are redirected to a secure page hosted on the provider's system. This handles all the payment relevant stuff (secure input of credit card, ... you really don't want to know the customers credit card information!)
once the checkout is completed, the payment provider calls a webhook at your backend sending you all the necessary information about the customer (name, purchased item, transaction id, ...)
you process that information at your backend, and store it somewhere. You can make some infomation available to the frontend for instance via the transaction id
the fontend will also get the transaction id from the SDK, so it can query your backend using this transaction id. What information you want/need to expose to the frontend is completely up to you.
Typically, there is absolutely no need to expose any other of your communication between your backend and paymentprovider via API, let alone forward data from the payment provider to the frontend. Especially, if anybody can access your API without authentication. Of course, you would probably need also some administrative API access too, but we agree, that this is certainly protected by some strong authentication.
Upvotes: 2