如何在一个浏览器中处理两个具有一个后端CSRF问题的网站?

时间:2018-01-16 03:48:25

标签: javascript python django django-rest-framework csrf

如何在一个浏览器中处理独立的主页和管理网站CSRF问题?

我们已经为它创建了一个主页网站前端和一个管理网站前端(有两个前端),在前端使用JavaScript。 因为两个站点都很大,所以我们将它们作为vhost放在Nginx中。他们是两个网站。我使用Python(Django)编写一个后端,两个站点都调用一个后端。

主页使用Nginx的default.conf,管理网站使用vhosts/admin.conf

这是测试域:

http://www.ajw123.xyz作为主页。
  http://admin.ajw123.xyz作为管理员网站。

我的麻烦是当我在浏览器的主页上使用帐户登录时:

enter image description here

然后我使用该帐户登录管理网站(或其他帐户),抛出CSRF令牌错误:

enter image description here

您看到csrftoken都是:

csrftoken=L5bRGEXDvW9dJaXsanLlMTOrxxGpxJCw6vji1zQtjzYrskOq0FBjQtfkhvFKFDmj; 

在预览中:

enter image description here

  

CSRF失败:CSRF令牌丢失或不正确。

我将Django-Rest-Framework用于其他API,我们的前端同事编写两个站点(一个是普通用户前端和后端站点,另一个是管理员的后端站点),两者都使用我的其余API

3 个答案:

答案 0 :(得分:3)

问题在于我在XY problem的一个例子。在下面的文字中,我将回到我的主张并解释它。

OP使用Django REST Framework编写了一个REST API。最初省略这些信息导致很少关注。在包含这些信息后,事情变得更加清晰。

让我们首先回顾一些关于REST API的基础知识。 REST API与语言无关。它并不关心客户编写的语言,而且客户也不关心API编写的语言。可以通过不同方式访问(使用)REST API:从命令行使用curl;来自用任何编程语言编写的脚本;来自使用(最有可能)JavaScript(或JavaScript框架)的浏览器。

由于有两个网站在使用API​​,因此OP希望为他们提供对API的访问权限。出现的障碍是CSRF(Cross Site Request Forgery) Django使用CSRF令牌实施了CSRF保护。这意味着我们保护我们的网站免受来自其他网站的请求,通常可以将表格发布到我们的网站。

在实际情况下,客户端是托管在不同域上的两个不同网站,因此来自它们的请求来自不同的站点。 OP真正想知道的是:
"如何授予或限制访问使用我的API的其他网站?"
而不是:
"如何处理CSRF问题?"

Django REST Framwork的官方文档有一个专门讨论这个问题的页面:
Working with AJAX, CSRF & CORS

这是CORS的部分:

  

跨源资源共享是一种允许客户端与托管在不同域上的API进行交互的机制。 CORS的工作原理是要求服务器包含一组特定的标头,允许浏览器确定是否以及何时允许跨域请求。

     

在REST框架中处理CORS的最佳方法是在中间件中添加所需的响应头。这可确保透明地支持CORS,而无需更改视图中的任何行为。

     

Otto Yiu维护着django-cors-headers包,已知它可以正常使用REST框架API。

我会强调第一句话:

  

跨源资源共享是一种允许客户端与托管在不同域上的API进行交互的机制。

确实如此。 OP希望允许客户端与托管在不同域上的API进行交互 最后一句建议使用django-cors-headers,这是问题的解决方案 有关应用程序使用的所有详细信息,请参阅其文档。

答案 1 :(得分:2)

CSRF令牌本质上是一个可检索的cookie 默认情况下,对于每个django应用,此Cookie的名称为csrftoken

您需要使用CSRF_COOKIE_NAME设置更改至少一个Cookie的名称(在settings.py中)。

然后你的同事可以通过以下AJAX调用检索该cookie:

// 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');

有关更复杂的用途,请查看文档:{​​{3}}

<小时/> 类似的案例:https://docs.djangoproject.com/en/2.0/ref/csrf/

答案 2 :(得分:2)

感谢@cezar和@JohnMoutafis,我阅读了CORS的文档:

  

跨源资源共享是一种允许客户端与托管在不同域上的API进行交互的机制。 CORS的工作原理是要求服务器包含一组特定的标头,允许浏览器确定是否以及何时应允许跨域请求。

然后我安装了django-cors-headers,然后使用它。

我设置了CORS_ORIGIN_WHITELIST

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

现在它运作正常。

再次感谢你。