【问题标题】:Django X-CSRFToken have been set but still get 403 forbiddenDjango X-CSRFToken 已设置但仍被禁止 403
【发布时间】:2015-11-06 01:34:18
【问题描述】:

我开发了一个 Django 文件上传 API,它从客户端接收发布的数据并将数据保存为文件。

根据Django CSRF manual,HTTP 请求标头应设置 X-CSRFToken 为 csrftoken cookie 值。我已经通过下面的代码设置了 X-CSRFToken,但是 POST 请求仍然被 Django 服务器禁止(403),如下图所示。

$(document).ready(function(){
    var authid
    $.get("http://localhost:8000/v1/getAuthID?username=testuser1&password=123", function(data){
        authid = data["authid"];
        var csrftoken = $.cookie('csrftoken');
        console.log(csrftoken);

        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        });

        url = "http://localhost:8000/v1/file".replace("{authid}", authid).replace("{token}", csrftoken)
        $.post(url, function(data){
        })
    })
})

您是如何通过向 Django 服务器发送 POST 请求来克服 Django CSRF 的?

谢谢!

【问题讨论】:

  • 是什么让你如此确定这是一个 CSRF 问题?乍一看,您的 CSRF 处理没有任何问题。
  • 我收到“CSRF 验证失败。请求中止。”当我检查 403 响应时。当 X-CSRFToken 添加代码被移除时,我可以得到相同的响应。
  • 好的,你能检查一下POST请求中发送的cookie是否与header匹配吗?
  • 感谢@knbk 的检查!如果我在浏览器中清除了以前的 cookie,我将永远无法获得名为“csrftoken”的 cookie。
  • 似乎 Django 没有向客户端发送 cookie csrftoken

标签: python django csrf django-csrf


【解决方案1】:

将 ajaxSetup 移到 AJAX 成功函数之外,因为它是请求所必需的,而不是在它之后。

$(document).ready(function(){
    var authid;
    var csrftoken = $.cookie('csrftoken');
    console.log(csrftoken);

    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    });


    $.get("http://localhost:8000/v1/getAuthID?username=testuser1&password=123", function(data){
        authid = data["authid"];

        url = "http://localhost:8000/v1/file".replace("{authid}", authid).replace("{token}", csrftoken)
        $.post(url, function(data){
        })
    })
})

【讨论】:

  • 感谢您的帮助:) 但是您的代码仍然出现 403 错误。
  • 您的控制台屏幕截图请求 localhost:8003 但您的代码 sn-p 是 localhost:8000 是否是拼写错误,或者这就是意图?
  • JS在本地网站localhost:8003运行。 Django 服务器在 localhost:8000 运行。
  • 我认为问题在于,除非您使用 Django 服务器在 :8000 上生成的 csrf 令牌/cookie,否则您在执行跨站点请求时将无法解决此问题。它可以在本地工作,但在生产中,除非您使用相同的域/子域,否则您会遇到问题
  • 感谢@justcompile,CORS 已由为 * 设置的 Access-Control-Allow-Origin 启用。所以我认为这不是跨域问题。
【解决方案2】:

我使用下面的 javascript 代码来处理 ajax 调用的整个 CSRF 主题:

// This function gets cookie with a given name
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('csrftoken');

/*
The functions below will create a header with csrftoken
*/

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
    // test that a given url is a same-origin URL
    // url could be relative or scheme relative or absolute
    var host = document.location.host; // host + port
    var protocol = document.location.protocol;
    var sr_origin = '//' + host;
    var origin = protocol + sr_origin;
    // Allow absolute or scheme relative URLs to same origin
    return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
        (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
        // or any other URL that isn't scheme relative or absolute i.e relative.
        !(/^(\/\/|http:|https:).*/.test(url));
}

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
            // Send the token to same-origin, relative URLs only.
            // Send the token only if the method warrants CSRF protection
            // Using the CSRFToken value acquired earlier
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

只需在 JQuery 之后包含它。

【讨论】:

  • 感谢@Danial 提供代码:)。 getCookie('csrftoken') 不适用于我的情况。我没有使用django模板,和django开发的api只通过js进行通信。所以我无法获得 cookie 'csrftoken'。这似乎是因为 Ajax 获取的响应 cookie 无法设置浏览器 cookie。我还在研究它... ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-13
  • 2016-04-02
  • 2021-10-08
  • 2021-07-08
  • 2016-10-10
  • 2017-05-16
  • 1970-01-01
相关资源
最近更新 更多