Frontend <-> Backend: Secure Stripe Integration - stripe-payments

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).
How do I secure the client-backend communication?
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).

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.

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.

Related

Ways to secure API that do not require authentication, to be called only from one pre-defined consumer

I have currently developed a backend app that has some important functionalities. I want to consume my backend endpoints from my frontend but I want to be sure that only my fronted calls the backend endpoint and no other. Currently anyone that access my web-app can take advantage of the functionalities (I do not require any user registration or authentication).
How can I be safe that my backend is not being called form other possible malicious attackers that may try to steal the functionalities of my backend?
I have read some other posts regarding solutions how to secure a backend app that do not require user authentication but none has a precise and secure way for that. Some say enabling CORS but during my experience I can say that CORS can be manipulated easily with the help of a simple browser plugin. (not speaking about mobile apps that do not consider it at all)
I would really appreciate if I would have some opinions in case of a web-frontend-app, mobile app and other backend systems that would try to call my API and how can I stop them.
Typical front-end authentication would be best (OpenID, ...).
If you want something different, you could check on your backend whether a specific header with a specific token is sent in the query. If it is not then you send back a 401 HTTP code.
This requires that your customers somehow get that token (through some registration process, probably) and then keep it long-term (it can be stored in LocalStorage but can be lost when cleaning up the browser)
OWASP Authentication is a good source of information.

Should the server to server authentication include User on which behalf the request is made?

I am going to implement security (using Identity Server 4). I have mobile application (front end) and few microservices (back end).
General scenario is that User_John calls Service_A_API using User-JWT token (obtained with Device flow). In order for Service_A to complete request, it has to access some data from Service_B. Service_A is calling Service_B using Server2Server-JWT token (obtained with Client credentials flow).
Server2Server-JWT is "Full access" token, allowing Service_A to do operations on any user on Service_B (e.g. it can delete user's order, update user's money balance, etc.)
Concerns that I have:
Is it correct to assume that Server2Server-JWT can have some long lifetime (e.g. 10-20 minutes) and it can be used for many requests originated from many different users?
Assuming Service_A and B are hosted in AWS (Dockers), is the Server2Server-JWT secure in those service's memory? What if (and how) the Server2Server-JWT get stolen?
Should Service_A request new Server2Server-JWT token for every user to call Service_B (and e.g. store this UserId in Claims)? Or is it safe to assume that Server2Server-JWT is safe in memory, and can be reused for any user request within the lifetime span of the full access Server2Server-JWT token?
Is Hybrid flow an answer to create a Server-to-server token on behalf of a user? Or is it something else?
My source of info are:
http://docs.identityserver.io/en/latest/topics/grant_types.html
https://www.pluralsight.com/courses/asp-dotnet-core-oauth2-openid-connect-securing
I definitely can answer the last question and only try with the rest.
Hybrid is a kind of interactive flow where one app has both client and server parts. Interactive means that a user goes through the IdP's portal to get authenticated.
Mobile apps usually run Authorization Code authorization flow with PKCE extension which all together behave pretty similar to hybrid where the "client" is a mobile browser and the "server" is the app itself.
No place for an API. But... you can look into the Extension Grant docs. Allows to implement Service Credentials on behalf of a user, exactly what you want, but... probably you don't need that with AWS.
They offer Network firewalls built into Amazon VPC, and web application firewall capabilities in AWS WAF to create private networks, and control access to your instances and applications. Together with "Customer-controlled encryption in transit with TLS across all services" that might be more than enough. The decision is yours.

Do I need to host the backend server for Stripe\Braintree payment gateway after I move the app to production?

if anyone could give me a clear high level answer that would be great. I want to integrate a payment gateway into my app eg: Strip/Braintree, and I have gotten it all working to the testing part but now I am wondering for me to move it to production do I need to host the back end server for retrieving the tokens myself?
Currently I hosted the test server locally to test that it works. But what now? Do I need to host this on a server for all time so my app can get its tokens?
Please help.
Yes, you have to.
You can start with a Virtual Machine at DigitalOcean or Vultr. Replicate your test environment there, then harden the server, etc.
If you're new to that then I recommend you to find someone who has experience setting up servers in production environments.
Thanks for your help. I spoke with Stripe and below was there response. They confirmed that you do need a server backend all the time.
--
Unfortunately, we don’t provide any hosted solutions when working with app based payment flows—you would need to have a back-end setup in place or use a serverless solution such as Heroku, both for your eventual move to a production environment and also while in development to test your back-end.
Generally speaking, you’ll use our SDKs when building your app to implement our client-side framework enabling you to securely collect and tokenize payment details from customers from within your app. However, the back-end server is where you’ll actually make requests to Stripe when you need to create a charge, refund a payment or take some other API related action.
Additionally, your back-end server will play a critical role as that’s where you’ll need to generate the ephemeral keys that will be used as the client-side session credentials for the app’s user. The use of ephemeral keys will facilitate the retrieval and updating of customer objects in Stripe for a given user (the persistent creation and use of individual customer objects is a default behavior for our mobile SDKs), but will ensure that your Stripe account’s secret API keys remain protected (public API keys are still used in the client).

Setup API that only your webserver can see it

So I want to have nginx serve up my react app that uses an API that is setup to make all the API calls for me. I want to do this so I can guard my API key and secret. So the API server is running on port 9001 and my react app is making api calls to to http://localhost:9001/api/v1/token. It works just fine. The issue I have is, how can I stop someone from doing the following to get a token?
curl -X POST --header "referer: http://localhost:8081" -i http://localhost:8081/api/v1/token
Thanks
If what you're asking is how you allow only your react app to use your API server, then the answer is you can't really.
Any request made from the browser has to be made to a server that can be reached lots of other ways (such as your Curl example). You can't allow only requests made from your React code and disallow all other attempts to talk to your API server because at the lowest level, these are all just http requests. Any determined hacker can just watch what the browser sent from your React app and make an http request that looks just like it. This is a fundamental design characteristic of how apps in a web browser work.
That said, there are some things you can do to "protect" your API server from abuse.
1. Require some form of account or authentication. This will at least require a hacker to make an account in your system and use that account to access your API server (more on this later).
2. Implement rate limiting so that an individual account (detected based on the credentials in the previous step) is only allowed certain frequency or pattern or access. At the very least this protects your API server from being overly abused by one bad actor.
3. Implement abuse control. If one particular account is regularly abusing the API server (hitting rate limit controls and generally using way more resources on your API server than any reasonable normal browser user ever would), then you can ban that account.
Services such as Google maps implement all three of the above in their efforts to protect the integrity of their API servers.
There are other techniques such as embedding an ever changing token into the web page that is then required with each subsequent call to the API server, but a determined hacker will just scrape the token from the web page and then use it until it expires so this is really just another obstacle for the hacker to get around, not an actual roadblock.

How to restrict Firebase data modification?

Firebase provides database back-end so that developers can focus on the client side code.
So if someone takes my firebase uri (for example, https://firebaseinstance.firebaseio.com) then develop on it locally.
Then, would they be able to create another app off my Firebase instance, signup and authenticate themselves to read all data of my Firebase app?
#Frank van Puffelen,
You mentioned the phishing attack. There actually is a way to secure for that.
If you login to your googleAPIs API Manager console, you have an option to lock down which HTTP referrer your app will accept request from.
visit https://console.developers.google.com/apis
Go to your firebase project
Go to credentials
Under API keys, select the Browser key associated with your firebase project (should have the same key as the API key you use to initialize your firebase app.)
Under "Accept requests from these HTTP referrers (web sites), simply add the URL of your app.
This should only allow the whitelisted domain to use your app.
This is also described here in the firebase launch-checklist here: https://firebase.google.com/support/guides/launch-checklist
Perhaps the firebase documentation could make this more visible or automatically lock down the domain by default and require users to allow access?
The fact that someone knows your URL is not a security risk.
For example: I have no problem telling you that my bank hosts its web site at bankofamerica.com and it speaks the HTTP protocol there. Unless you also know the credentials I use to access that site, knowing the URL doesn't do you any good.
To secure your data, your database should be protected with:
validation rules that ensure all data adheres to a structure that you want
authorization rules to ensure that each bit of data can only be read and modified by the authorized users
This is all covered in the Firebase documentation on Security & Rules, which I highly recommend.
With these security rules in place, the only way somebody else's app can access the data in your database is if they copy the functionality of your application, have the users sign in to their app instead of yours and sign in/read from/write to your database; essentially a phishing attack. In that case there is no security problem in the database, although it's probably time to get some authorities involved.
Update May 2021: Thanks to the new feature called Firebase App Check, it is now actually possible to limit access to your Realtime Database to only those coming from iOS, Android and Web apps that are registered in your Firebase project.
You'll typically want to combine this with the user authentication based security described above, so that you have another shield against abusive users that do use your app.
By combining App Check with security rules you have both broad protection against abuse, and fine gained control over what data each user can access.
Regarding the Auth white-listing for mobile apps, where the domain name is not applicable, Firebase has
SHA1 fingerprint for Android apps and
App Store ID and Bundle ID and Team ID (if necessary) for your iOS apps
which you will have to configure in the Firebase console.
With this protection, since validation is not just if someone has a valid API key, Auth domain, etc, but also, is it coming from our authorized apps and domain name/HTTP referrer in case of Web.
That said, we don't have to worry if these API keys and other connection params are exposed to others.
For more info, https://firebase.google.com/support/guides/launch-checklist

Resources