How to Avoid exposing the Backend API

I’ve been learning how to use react and nextJS to build a frontend for one of my projects. I’m using Flask to build the API backend server that will provide the main functionality.

I want to limit abuse of the API server and came across several options.

Options

CORS

CORS is a mechanism that’s enforced by the browser to limit access to a server’s resources. However, since it’s only a browser enforced mechanism, a user can replay the request using another method like curl.

It’s not useful in protecting my backend API from unwanted calls, but it can be used to prevent other websites from fetching resources from my backend and showing it to users. CORS is mostly used to prevent a malicious script from requesting resources from a site that the user is logged in to (think bank), since the request will usually send over the user’s cookies as well. See “Same origin policy”.

Session Authentication - Bearer Tokens / JWT

The next common method is to implement an authentication mechanism to limit access only to authorized users. This is a must for any API and there’s a great survey of all the different schemes that could be used to implement this and their tradeoffs.

However, this doesn’t cover the case of wanting to expose a public API without authentication, like a weather service or a chat-bot for your blog.

Rate limiting

We can use rate limiting to prevent abuse of the API and its resources. There are several rate limiting strategies that could be used and scopes to apply the limits to.

In my case, I would want to apply a limit on a per client basis of something like 100 reqs/minute. I’m planning to use the flask-limiter library to apply the limits on my endpoints using the client’s ip-address. It uses a fixed window strategy, but I prefer a leaky window strategy that would prevent bursts.

Don’t make Client-side Requests

If I don’t intend for anyone to use my API except the frontend, I could write the frontend in a way where only the Frontend server makes requests to the Backend server. I could then secure the connection using a firewall that only permits access to the Frontend server mTLS and/or use mTLS. This layer of security prevents client web browsers from completing a request due to a coding mistake on my end that had the client attempt to complete the request instead of the server. It’s a tradeoff of making the website resilient to mistakes vs. exposing the backend server.

NextJS supports this using server actions.

Summary

For my project, I’m planning to avoid API exposure by having the Frontend server make the requests to the API and I’m going to implement rate-limiting for the API since I do want general API access to be available. I will have to limit on something other than IP if I do the requests from the Frontend server, some kind of browser fingerprinting.

As I continue to develop my project and as user sign up and authentication I should keep in mind the OWASP Top 10