通过我的AJAX帖子,我可以使用一些帮助来遵守Django的CSRF保护机制。我遵循了这里的说明:

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

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

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

我把一个警告打印getCookie('csrftoken')的内容之前的xhr。setRequestHeader调用,它确实被一些数据填充。我不确定如何验证令牌是正确的,但我被鼓励它正在寻找和发送一些东西。

但是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 / remember / HTTP/1.1" 403 2332

我肯定我遗漏了什么,也许很简单,但我不知道是什么。我在SO周围搜索了一下,看到了一些关于通过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))

谢谢你的回复!


当前回答

对于遇到这种情况并试图调试的人:

1) django CSRF检查(假设你发送了一个)在这里

2)在我的例子中,设置。CSRF_HEADER_NAME被设置为“HTTP_X_CSRFTOKEN”,我的AJAX调用正在发送一个名为“HTTP_X_CSRF_TOKEN”的头,所以东西不工作。我可以改变它在AJAX调用,或django设置。

3)如果你选择更改服务器端,找到django的安装位置,并在csrf中间件中抛出一个断点。如果你使用的是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令牌正确地来自请求。元

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

其他回答

更新2022

在CSRF攻击中,无辜的终端用户被攻击者欺骗,提交了一个他们不打算提交的web请求

选项1

from django.views.decorators.csrf import csrf_exempt
from django.http.response import JsonResponse


@csrf_exempt
def commentDeletePost(request):
    if request.is_ajax() and request.method == 'POST':
        try:
            comment = Comment.objects.get(pk=request.POST['pk'])
            if comment.author != request.user:
                return JsonResponse({'e': 'Forbidden'}, status=403) 
            comment.delete()
            return JsonResponse({}, status=200)
        execpt Comment.DoesNotExist:
            return JsonResponse({'e': 'Not Found'}, status=404)

选项2

<div id="csrf">
    {% csrf_token %}
</div>
<script type="text/javascript">
    window.crud = {
        commentDelete: function(
            pk, 
            success,
            error, 
        ){
            $.ajax({
                headers: {'X-CSRFToken': document.getElementById('csrf').querySelector('input').value},
                type: "POST", 
                url: "{% url 'comment-delete-post' %}",
                data: {
                    pk: pk,
                }, 
                success: success, 
                error: error,
            })
        }, 
    }
</script>

two options have its own advantage. First option will discard csrf token, which will not protecte your site from csrf attacks, but it will allow user to send more than one request with same Ajax function. the second option will restrict user to send one Ajax request only since csrf token can only be used once, but it is more secure. I personally prefer option 1, since Ajax functions such as like, star, unlike requires more than one Ajax call, and it is not a risky function to allow user call more than once.

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

然后你就知道误差是什么了。

在我的情况下,问题是与nginx配置,我已经从主服务器复制到一个临时禁用https,在第二个过程中不需要。

我不得不注释掉配置中的这两行,以使它再次工作:

# uwsgi_param             UWSGI_SCHEME    https;
# uwsgi_pass_header       X_FORWARDED_PROTO;

与所选答案相关,只是想对所选答案进行补充。

在这个回答中,关于. ajaxsetup(…)的解决方案。在Django settings.py中,如果你有

CSRF_USE_SESSIONS = True

这将导致所选的答案根本不起作用。在实现所选答案的解决方案时,删除该行或将其设置为False对我有用。

有趣的是,如果你在Django settings.py中设置了以下内容

CSRF_COOKIE_HTTPONLY = True

此变量不会导致所选答案的解决方案停止工作。

CSRF_USE_SESSIONS和CSRF_COOKIE_HTTPONLY都来自这个官方的Django文档https://docs.djangoproject.com/en/2.2/ref/csrf/

(我没有足够的代表来评论,所以我张贴我的输入一个答案)

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

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