CORS、Ajax 和 CSRF

Posted

技术标签:

【中文标题】CORS、Ajax 和 CSRF【英文标题】:CORS, Ajax, and 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 不同的域中。有什么建议?

【问题讨论】:

您解决了这个问题吗?听起来你和我有同样的问题。 不,从未解决。 如果这个问题还没解决,可以试试:cistoner.org/blog/minhaz/2014/03/08/… 【参考方案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。我会调查一下。谢谢。

以上是关于CORS、Ajax 和 CSRF的主要内容,如果未能解决你的问题,请参考以下文章

CORS $.ajax 会话 cookie(访问控制允许凭据和 withCredentials=true)

AJAX、CORS、Chrome 和 HTTP 错误代码 (401,403,404,500) 的推荐解决方案

如何使用 Web 服务和 jQuery Ajax 启用 CORS

使用 ajax 发出 http 请求以获得基本授权和 cors

Ajax 跨域 异步 CORS

带有 Express.js 和 jQuery.ajax 的 CORS