最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to deal with two websites with one backend CSRF issue in one browser? - Stack Overflow

programmeradmin5浏览0评论

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:

as the home website.
as the admin website.

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

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

You see the csrftoken both are:

csrftoken=L5bRGEXDvW9dJaXsanLlMTOrxxGpxJCw6vji1zQtjzYrskOq0FBjQtfkhvFKFDmj; 

In the preview:

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.

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:

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

You see the csrftoken both are:

csrftoken=L5bRGEXDvW9dJaXsanLlMTOrxxGpxJCw6vji1zQtjzYrskOq0FBjQtfkhvFKFDmj; 

In the preview:

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.

Share Improve this question edited Jan 21, 2018 at 21:40 Martijn Pieters 1.1m321 gold badges4.2k silver badges3.4k bronze badges asked Jan 16, 2018 at 3:48 aircraftaircraft 27k29 gold badges101 silver badges174 bronze badges 8
  • 1 Use different cookie name on each one – charlietfl Commented Jan 16, 2018 at 11:28
  • @charlietfl How to do with that? do you mean in Nginx? – aircraft Commented Jan 16, 2018 at 11:38
  • In whatever Django module that manages the csrf. i'm not a django dev but have done this in other environments – charlietfl Commented Jan 16, 2018 at 11:43
  • @charlietfl Thank you anyway. – aircraft Commented Jan 16, 2018 at 11:52
  • 2 This is very important information you omitted in your question. So basically your Django project is a REST API. The frontends (home and admin) are clients consuming the API. Right? Did you read this page of the documentation? – cezar Commented Jan 18, 2018 at 7:53
 |  Show 3 more ments

3 Answers 3

Reset to default 5 +50

The question is in my opininon an example of XY problem. In the following text I'll e 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 mand 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 ing 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 remends 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.

CSRF token is essentially a cookie which is retrievable.
By default, the name of this cookie is csrftoken for every django app.

You need to change the name of at least one of the cookies with the CSRF_COOKIE_NAME setting (in your settings.py).

Then your colleagues can retrieve that cookie with the following AJAX call:

// using jQuery
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('name_of_your_token');

For more plicated uses check the documentation: https://docs.djangoproject./en/2.0/ref/csrf/


A similar case: Multiple Django sites on the same domain - CSRF fails

Thanks @cezar and @JohnMoutafis, I read the doc of 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.

Then I installed the django-cors-headers, and use it.

I set the CORS_ORIGIN_WHITELIST:

CORS_ORIGIN_WHITELIST = (
    'http://10.10.10.102:8000', # normal user site
    'http://10.10.10.102:8080', # admin backend site
)

Now it works fine.

Thank you again.

发布评论

评论列表(0)

  1. 暂无评论