【问题标题】:CORS, Ajax, and CSRFCORS、Ajax 和 CSRF
【发布时间】:2014-03-08 12:51:01
【问题描述】:

django 应用程序中的 CSRF 预防支持通过 cookie 将 CSRF 令牌向下发送到客户端,并在标头 (X-CSRFToken) 或 cookie 中接受来自客户端的 CSRF 令牌。这适用于非 CORS、非 AJAX Web 应用程序。但是,如果您 a) 有一个通过 AJAX 与服务器通信的单页 Web 应用程序,并且 b) 单页 Web 应用程序托管在与服务器 (CORS) 不同的域中,则它似乎不起作用。

问题是由于 CORS 限制,单页 webapp(来自 domain1)无法使用 xhr.getResponseHeader 或 getCookie 读取服务器域(domain2)cookie。鉴于无法读取 cookie,javascript webapp 如何将适当的 CSRF 令牌发送到服务器?

xhr.getResponseHeader api 被限制检索 Set-Cookie 或 Set-Cookie2 标头(按规范),并且各种支持 CORS 的浏览器似乎强制执行此限制。同理,getCookie JS 函数会读取 webapp 域(domain1)中所有非 httpOnly cookie,但不会读取服务器在其域(domain2)中设置的那些。

这在非 CORS 情况下不是问题,但在我们的应用程序中,我们希望将 API 托管在与客户端 webapp 不同的域中。有什么建议?

【问题讨论】:

标签: jquery ajax cookies cors django-csrf


【解决方案1】:

我想我遇到了同样的问题,并通过结合服务器端的东西和客户端的东西来解决它。服务器端(Django-Python):

origin = request.META.get('HTTP_ORIGIN', None)
if origin and origin in settings.safe_origins:
    response['Access-Control-Allow-Origin'] = origin
    response['Access-Control-Allow-Credentials'] = 'true'
    response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
    response['Access-Control-Allow-Headers'] = request.META.get('Access-Control-Allow-Headers', 'x-requested-with, X-CSRFToken',)
    response['Access-Control-Max-Age'] = 15
    response['Allow'] = 'GET, POST, PUT, DELETE, OPTIONS'

客户端启动时:

$.ajaxPrefilter(function(options, originalOptions, jqXHR)
{
    options.crossDomain =
    {
        crossDomain: true
    };
    options.xhrFields =
    {
        withCredentials: true
    };
});

function csrfSafeMethod(method)
{
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup(
{
    crossDomain: false, // obviates need for sameOrigin test
    beforeSend: function(xhr, settings)
    {
        if (!csrfSafeMethod(settings.type))
        {
            xhr.setRequestHeader("X-CSRFToken", csrf);
        }
    }
});

然后在 $.ajax 中调用它们自己:

$.ajax(
{
    type: "POST",
    url: theUrl,
    data: theData,
    contentType: 'application/x-www-form-urlencoded',
    dataType: 'json',
    xhrFields:
    {
       withCredentials: true
    }
});

对我来说,我最想念的就是这部分:

xhrFields:
{
   withCredentials: true
}

希望这对某人有所帮助。

【讨论】:

  • 有趣。我相信我们正在做你上面描述的所有事情,除了在 ajax 请求中设置 crossDomain: false 。我认为我们已经明确设置了 crossDomain: true。我会调查一下。谢谢。
猜你喜欢
  • 2015-08-22
  • 2014-05-01
  • 2012-08-16
  • 2018-08-20
  • 1970-01-01
  • 2013-07-12
  • 2016-02-14
  • 2015-07-25
  • 1970-01-01
相关资源
最近更新 更多