python - csrf验证失败请求被中断




Django CSRF检查失败,发出Ajax POST请求 (12)

对于遇到此问题并正在尝试调试的人员:

1)django csrf检查(假设你正在发送一个)在here

2)在我的情况下, settings.CSRF_HEADER_NAME被设置为'HTTP_X_CSRFTOKEN',并且我的AJAX调用正在发送一个名为'HTTP_X_CSRF_TOKEN'的头部,所以东西不起作用。 我可以在AJAX调用或django设置中更改它。

3)如果你选择改变它的服务器端,找到你的django的安装位置,并在csrf middleware抛出一个断点。如果你使用的是virtualenv ,它会是这样的: ~/.envs/my-project/lib/python2.7/site-packages/django/middleware/csrf.py

import ipdb; ipdb.set_trace() # breakpoint!!
if request_csrf_token == "":
    # Fall back to X-CSRFToken, to make things easier for AJAX,
    # and possible for PUT/DELETE.
    request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

然后,确保csrf标记正确地源自request.META

4)如果你需要改变你的头文件等 - 改变你的设置文件中的变量

我可以通过我的AJAX文章使用一些帮助来遵守Django的CSRF保护机制。 我按照这里的方向:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/

我已经完全复制了他们在该页面上的AJAX示例代码:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

我在xhr.setRequestHeader调用之前放置了一个打印getCookie('csrftoken')的内容的警报,并且它确实填充了一些数据。 我不确定如何验证令牌是否正确,但我鼓励它发现并发送内容。

但是Django仍然拒绝我的AJAX帖子。

这是我的JavaScript:

$.post("/memorize/", data, function (result) {
    if (result != "failure") {
        get_random_card();
    }
    else {
        alert("Failed to save card data.");
    }
});

这是我从Django看到的错误:

[23 / Feb / 2011 22:08:29]“POST / memorize / HTTP / 1.1”403 2332

我确定我错过了一些东西,也许这很简单,但我不知道它是什么。 我搜索了一下,看到了一些关于通过csrf_exempt装饰器关闭我的视图的CSRF检查的信息,但是我发现它没有吸引力。 我已经试过了,它可以工作,但我宁愿让我的POST按照Django设计的方式工作,如果可能的话。

以防万一它是有用的,这是我的观点在做什么的主要内容:

def myview(request):

    profile = request.user.profile

    if request.method == 'POST':
        """
        Process the post...
        """
        return HttpResponseRedirect('/memorize/')
    else: # request.method == 'GET'

        ajax = request.GET.has_key('ajax')

        """
        Some irrelevent code...
        """

        if ajax:
            response = HttpResponse()
            profile.get_stack_json(response)
            return response
        else:
            """
            Get data to send along with the content of the page.
            """

        return render_to_response('memorize/memorize.html',
                """ My data """
                context_instance=RequestContext(request))

感谢您的回复!


{% csrf_token %}<form></form> html <form></form>模板放在<form></form>

翻译为:

<input type='hidden' name='csrfmiddlewaretoken' value='Sdgrw2HfynbFgPcZ5sjaoAI5zsMZ4wZR' />

那么为什么不把它像这样写在你的JS中呢:

token = $("#change_password-form").find('input[name=csrfmiddlewaretoken]').val()

然后通过它,例如做一些POST,如:

$.post( "/panel/change_password/", {foo: bar, csrfmiddlewaretoken: token}, function(data){
    console.log(data);
});

一个CSRF令牌分配给每个会话(即每次登录时)。 因此,在希望获取用户输入的某些数据并将其作为ajax调用发送给受csrf_protect装饰器保护的某个函数之前,请尝试在从用户获取此数据之前查找正在调用的函数。 例如,必须呈现用户输入数据的某个模板。 该模板正在被某个函数渲染。 在这个函数中,你可以得到csrf标记,如下所示:csrf = request.COOKIES ['csrftoken']现在在上下文字典中传递这个csrf值,使得模板被渲染。 现在在这个模板中写下这一行:现在在你的javascript函数中,在发出一个jax请求之前,写下:var csrf = $('#csrf')。val()这会选择传递给模板的令牌的值,并将其存储在变量CSRF。 现在在进行ajax调用时,在您的发布数据中也传递此值:“csrfmiddlewaretoken”:csrf

即使你没有实现django表单,这也可以工作。

事实上,这里的逻辑是:你需要令牌,你可以从请求中获得。 因此,您只需要在登录后立即找出正在调用的函数。获得此令牌后,可以再次调用ajax来获取它,或者将它传递给您的ajax可访问的某个模板。


似乎没有人提到过如何在纯JS中使用X-CSRFToken头和{{ csrf_token }}来做到这一点,所以这里有一个简单的解决方案,您不需要通过cookies或DOM进行搜索:

var xhttp = new XMLHttpRequest();
xhttp.open("POST", url, true);
xhttp.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
xhttp.send();

使用Firefox和Firebug。 在触发ajax请求时打开“控制台”选项卡。 使用DEBUG=True您可以获得好的django错误页面,您甚至可以在控制台选项卡中看到呈现的ajax响应html。

然后你会知道错误是什么。


在我的情况下,问题在于我从主服务器复制的nginx配置到临时配置,禁用了https,这在进程中的第二个配置中不需要。

我必须在配置中注释掉这两行才能使其重新工作:

# uwsgi_param             UWSGI_SCHEME    https;
# uwsgi_pass_header       X_FORWARDED_PROTO;

如果您的表单在没有JS的情况下在Django中正确发布,您应该能够逐渐通过ajax进行增强,而不会发生任何黑客或混乱传递csrf标记。 只需序列化整个表单,并自动获取所有表单字段, 包括隐藏的csrf字段:

$('#myForm').submit(function(){
    var action = $(this).attr('action');
    var that = $(this);
    $.ajax({
        url: action,
        type: 'POST',
        data: that.serialize()
        ,success: function(data){
            console.log('Success!');
        }
    });
    return false;
});

我用Django 1.3+和jQuery 1.5+测试了这个。 显然这将适用于任何HTML表单,而不仅仅是Django应用程序。



我刚刚遇到了一些不同但类似的情况。 不是100%确定它是否可以解决您的问题,但是我通过设置POST参数'csrfmiddlewaretoken'并使用正确的cookie值字符串解决了Django 1.3的问题,该字符串通常由Django的带有'{%csrf_token%}'标记的模板系统。 我没有尝试Django,只是发生并在Django1.3上解决。 我的问题是,从表单中通过Ajax提交的第一个请求已成功完成,但第二次尝试从失败的完全相同,导致403状态,即使头文件'X-CSRFToken'正确放置了CSRF标记值如第一次尝试的情况一样。 希望这可以帮助。

问候,


接受的答案很可能是一条红鲱鱼。 Django 1.2.4和1.2.5之间的区别是需要针对AJAX请求的CSRF令牌。

我在Django 1.3上遇到了这个问题,这是由于CSRF cookie不是首先设置的。 除非必须,否则Django不会设置cookie。 因此,在Django 1.2.4上运行的独占或严重ajax站点可能永远不会向客户端发送令牌,然后需要该令牌的升级会导致403错误。

理想的解决方法在这里: http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#page-uses-ajax-without-any-html-form : http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#page-uses-ajax-without-any-html-form
但是你不得不等待1.4,除非这只是文档追踪代码

编辑

还要注意,后面的Django文档记录了jQuery 1.5中的一个错误,因此请确保您使用的是1.5.1或更高版本以及Django建议的代码: http://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#ajax : http://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#ajax


这是Django提供的一个不太详细的解决方案:

<script type="text/javascript">
// using jQuery
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
// set csrf header
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

// Ajax call here
$.ajax({
    url:"{% url 'members:saveAccount' %}",
    data: fd,
    processData: false,
    contentType: false,
    type: 'POST',
    success: function(data) {
        alert(data);
        }
    });
</script>

来源: https://docs.djangoproject.com/en/1.11/ref/csrf/https://docs.djangoproject.com/en/1.11/ref/csrf/


非jQuery的答案:

var csrfcookie = function() {
    var cookieValue = null,
        name = 'csrftoken';
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
};

用法:

var request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.setRequestHeader('X-CSRFToken', csrfcookie());
request.onload = callback;
request.send(data);




csrf