Django Rest + React + Flutter: how to restrict domain origin of requests - reactjs

I am currently building a web + mobile application.
My front end is developed using React and Axios (for API call requests). It is served directly by vercel on mydomain.com
My Mobile App is developed using the Flutter
My back end is developed using Django and Django Rest. It is served with apache2 on api.mydomain.com. It only serves API endpoints.
So the front-end, Mobile app, and back-end are separated.
I would like only my front-end (mydomain.com) and flutter app to be able to make API requests to my Django Rest backend.
I would like to prevent any other domains, any clients such as postman, insomnia, curl, or any script to make API requests to my backend.
I have already set CORS in Django Rest. However, I can still make requests to the backend using curl or any other client.
Do you have any idea of what I could do to achieve this?
Thanks a lot in advance for your answers.

CORS is enforced only by web browsers to prevent leaking information to unrelated pages that might request it. You need some kind of access control, either by authenticating the caller or limiting access to the endpoint.
Checking the Host header with get_host() may offer sufficient protection, depending on your server setup.
get_host() will tell you the value of the Host header in the request, which is data provided by the client so could be manipulated in any way. The Host header is an integral part of HTTP 1.1 in allowing multiple domains to be hosted at a single address so you might be able to depend on your server rejecting requests that aren't actually arriving from localhost with a matching header, but it's difficult to be certain.
It would likely be more reliable to check the client's network address and reject requests from all clients except those that are specifically allowed.
Check this question too.

Related

Quarkus REST API CORS configuration not working for consumer ReactJS app

I have a ReactJS UI that is served by a static NGINX web server and a Quarkus REST API server. Both are dockerized services, and the ReactJS app is supposed to use the Quarkus REST API to consume data/make requests. In the depiction below we can see this simple setup for my localhost dev enironment (both services are exposed and mapped to different localhost ports):
In the deployed production environment, these will services will likely correspond to different hosts/URLs. The problem is, even in the localhost setup i expectedly have the issue of CORS errors when i try to make calls to the REST API service from the ReactJS app running in the clients browser, e.g. during login:
I have to admit, i dont fully understand CORS in terms of where exactly one has to make changes/configs to allow them - but i was told i need to set them in the server i make requests to (which in this case is the Quarkus REST API). So i added this setting in the Quarkus app application.properties to just generally allow all requests:
quarkus.http.cors=true
(as shown in https://quarkus.io/guides/http-reference#cors-filter)
In reality i should probably change this to be more precise, however i still receive the same CORS error in my browser when running the react web app. I understand that i could also configure a proxy in the NGINX server to tunnel requests to the other service container potentially, but i would like to solve this through CORS configuration. Where do i have to make which configurations for this to work? Did i make a mistake with the Quarkus config?
It seems you cannot only set quarkus.http.cors=true for it to work and allow all requests, as per the Quarkus documentation. In my case i had to add more configurations, i.e.:
quarkus.http.cors=true
# This allows all origin hosts, should be specified if possible
quarkus.http.cors.origins=*
quarkus.http.cors.headers=accept, authorization, content-type, x-requested-with
quarkus.http.cors.methods=GET, POST, PUT, DELETE, OPTIONS

Proxy third party fetches

I'm asking for some help, maybe I'm missunderstanding some concepts and finally I dont know how to solve this requirement:
I have a create-react-app application deployed using Netlify.
Also my backend is deployed on AWS ECS.
I'm using AWS route 53 for routing frontend and backend to myapp.mydomain.com and api.mydomain.com respectively.
A client has a specific network config so only *.mydomain.com requests are allowed for his organization.
The problem resides on frontend because it uses many libraries, for example:
Checking network tab on browser I noticed thw following:
I'm using a giphy library, so it makes requests to api.giphy.com.
I'm using some google stuff like analytics and fonts, so I assume it will make requests to some google domain.
And so on...
As I understand this kind of fetches will be blocked by client network "firewall".
Adding more rules to said firewall is not an option (That was my first proposal to client but they only allows *.mydomain.com and no more)
So my plan B was implement a proxy ... but I dont have any idea of how to implement such solution.
It's possible to "catch" third party fetches, redirect them to my backend like api.mydomain.com/forward, so my backend would make real fetch and returns response given by said fetch to frontend?
The result desired should be, for example again, all fetches made to api.giphy.com should be redirected to api.mydomain.com/forward/giphy and same for all third-party fetches
I Googled a lot and now I'm very confused, any help is welcome!! Thanks devs!

NGINX: Block all external IPs except the server IP where ReactJS is hosted?

Can anyone help how to configure nginx so it only accepts the server IP where ReactJS is hosted?
Ive tried many options to no avail. I always see ReactJS is using the client IP where the user is currently browsing (because of I guess of its client-based nature). Unfortunately, I need to block all other request to protect my Django rest api from external requests. My Django app is having this nginx reverse proxy by the way. How do you guys do this?
I think you seriously misunderstood how your app works. Unless you are doing something really, really weird, it generally works like this:
The user's browser (the client) receives the ReactJS code from the server hosting it
The ReactJS code is executed in the user's browser
All requests for your REST API will originate from the user's browser executing the ReactJS code, i.e. coming from the client machine, not from the server hosting the ReactJS code
The server hosting the ReactJS code merely returns the ReactJS code to client, and doesn't even interact with the server hosting Django REST API
Thus, what you are attempting to do is misguided and in fact will just restrict your users.
As a side note, you may use several complicated techniques to be somewhat sure that the API requests do come from a browser executing your ReactJS code (i.e. a legitimate use of your API) rather than other tools, but that's far from a guarantee and in most cases serves no practical purpose anyway.

CloudFlare JS challenge is breaking my SPA

I have a React based SPA that is hosted via S3 on one subdomain, react.mydomain.com ... It communicates with a PHP REST API that is hosted on a VPS on another subdomain, api.mydomain.com . The api.mydomain.com is behind CloudFlare. The webapp is behind CloudFront since it is on AWS.
I am having issues w/ bot requests directly to the API flooding my VPS, and I would like to use the JS challenge functionality with CloudFlare to mitigate.
However, what seems to be happening is that users are able to load the React webapp (which is not behind CloudFlare). Then, the request that will prompt the JS challenge will fail with a 503 response instantly, because it is an AJAX request and it is incompatible with the Javascript challenge.
I thought I may be able to handle this by catching the error and redirecting. However, if I manually force my own browser to navigate to the api.mydomain.com URL, I will see the CloudFlare challenge and pass it. However, if I then navigate back to my react.mydomain.com SPA, the OPTIONS requests will fail because it cannot attach the cookie that tells CloudFlare it has passed.
I don't understand how to adjust my infrastructure so that I can take advantage of using the JS challenge. At the moment I am restricted to using rate limiting, but I have found that I am still letting in what seems like ~75% or more of the unwanted bot traffic through by the time I get severe enough that users start complaining.
If you have backend access, you may be able to use NPM and process.kill(process.pid) upon detection of a bot as a temporary solution.
I suggest not to host spa in s3 only file uploads or attachments to s3
Host on Ec2 and block all access through security Group Policy
only allow Cloudflare IP's
which are listed here https://www.cloudflare.com/ips/
You can also use Amazon AWS Lambda serverless for hosting instead of s3
https://aws.amazon.com/lambda/?c=ser&sec=srv

How can I send cross site PUT requests through GWT?

I am creating a web application using GAE/GWT. Front end GUI is a web client and the server is a RESTFUL server both running in GAE in different domains.
I am using json with padding to communicate with the server but discovered I won't be able to send a PUT/POST/DELETE request.
My application will be used to mainly used to query data (query: 85% of cases, modify data: 15%). All requests will be authenticated.
I am considering the following options.
1) For querying use JsonpRequestBuilder, for modifying create a proxy in the web client server side and hit the REST service through this proxy. Use GWT RPC to communicate to this proxy.
2) Make every request as a GET request in my REST service (including those that modify data) and use jsonp directly from web client.
I would prefer option 1) but option 2) seems less work to do.
Should 1) be my preferred option ?
Are there any problems with 2) given all my requests will be authenticated. ?
Is there any other easy approach to solve this problem ?
Regards,
Sathya
The simplest solution is to use CORS which allows you to send requests two different origins. But it is not so widely spread (check caniuse), so if you have to support IE8-9, it will not be enough for you.
In your case I would try to implement dual solution (e.g. CORS + server proxy). If browser supports CORS - send the request directly to the target server, if it doesn't - send request via proxy.
Sorry to ask but what is the advantage to have your client running on a different domain ? From what I understand your client's server will do nothing ...
If you are not the "owner" of the REST backend, maybe this backend should developp an authorization system for third party applications, like oauth2.
Then your application can talk backend to backend with a secured connection. You can use scribe to do that on your backend.

Resources