Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with two websites with one backend CSRF issue in one browser?

How to deal with the independent home website and admin website CSRF issue in one browser?

We have written a home website frontend and an admin website frontend for it (there are two frontends), using JavaScript in the frontend.
Because both sites are large, we have put them as vhost in Nginx. They are two sites. I use Python (Django) to write one backend, both sites invoke one backend.

The home website uses Nginx's default.conf, the admin website uses vhosts/admin.conf.

This is the test domain:

http://www.ajw123.xyz as the home website.
http://admin.ajw123.xyz as the admin website.

My trouble is when I use an account login on the home website in the browser:

enter image description here

Then I use the account to login to the admin website (or other accounts), the CSRF Token Error is thrown:

enter image description here

You see the csrftoken both are:

csrftoken=L5bRGEXDvW9dJaXsanLlMTOrxxGpxJCw6vji1zQtjzYrskOq0FBjQtfkhvFKFDmj; 

In the preview:

enter image description here

CSRF Failed: CSRF token missing or incorrect.

I use Django-Rest-Framework for the rest APIs, our frontend colleagues write two sites (one is normal user frontend and backend site, the other is admin's backend site), and both are using my rest APIs.

like image 692
aircraft Avatar asked Dec 24 '22 11:12

aircraft


1 Answers

The question is in my opininon an example of XY problem. In the following text I'll come back to my claim and explain it.

The OP has written a REST API using Django REST Framework. Omitting this information initially led to very low attention. After including this information the thing became much clearer.

Let's first recall some basics about REST APIs. A REST API is language agnostic. It doesn't care in which language the clients are written, and also the clients don't care in which language the API has been written. The REST API can be accessed (consumed) in different ways: from the command line using curl; from a script written in any programming language; from a browser using (most likely) JavaScript (or a JavaScript framework).

Since there are two websites consuming the API, the OP wanted to provide them access to the API. The obstacle that has arisen was CSRF (Cross Site Request Forgery).
Django has implemented CSRF protection with the use of CSRF tokens. This means we protect our website from requests from other websites, where usually a form can be posted to our website.

In the actuall case the clients are two different websites hosted on different domains, so the requests coming from them are from a different site. What the OP really wants to know is:
"How to grant or restrict access to other websites consuming my API?"
and not:
"How to deal with the CSRF issue?"

The official documentation of Django REST Framwork has a page dedicated to this issue:
Working with AJAX, CSRF & CORS

This is the section for CORS:

Cross-Origin Resource Sharing is a mechanism for allowing clients to interact with APIs that are hosted on a different domain. CORS works by requiring the server to include a specific set of headers that allow a browser to determine if and when cross-domain requests should be allowed.

The best way to deal with CORS in REST framework is to add the required response headers in middleware. This ensures that CORS is supported transparently, without having to change any behavior in your views.

Otto Yiu maintains the django-cors-headers package, which is known to work correctly with REST framework APIs.

I'll emphasise the first sentence:

Cross-Origin Resource Sharing is a mechanism for allowing clients to interact with APIs that are hosted on a different domain.

Exactly that is the case. The OP wants to allow clients to interact with his API that is hosted on a different domain.
The last sentence recommends the use of django-cors-headers which is the solution of the problem.
All further details about the use of the app can be found in its documentation.

like image 137
cezar Avatar answered Feb 15 '23 09:02

cezar