Django + jQuery:为什么CSRF验证在多个同时请求中失败

时间:2012-07-18 13:03:27

标签: jquery django csrf django-csrf

我遇到了以下情况(使用Django1.4和jQuery 1.7.1),我想了解: 我通过jQuery'ajax'函数提交一个表单,在此请求完成之前,我单击另一个提交相同表单但使用jQuery“submit”函数的元素。我收到的回复 - 403,CSRF验证失败。现在,当然,为了防止这个错误,它足以禁用多个同时提交(它们自己正常工作),但这无助于理解特定错误的来源。

任何人都能解释一下吗?每个会话生成一次csrf令牌,因此对于后一个请求,它不能是某种csrf不匹配。 这与jQuery handels请求的方式有关吗?

2 个答案:

答案 0 :(得分:0)

我认为你的代码存在问题。只需阅读django代码


此块中出现错误。

if not constant_time_compare(request_csrf_token, csrf_token):
            logger.warning('Forbidden (%s): %s',
                           REASON_BAD_TOKEN, request.path,
                extra={
                    'status_code': 403,
                    'request': request,
                }
            )
            return self._reject(request, REASON_BAD_TOKEN)

所以你的前端脚本发送csrf_token哪个和cookies(发送浏览器)不相等


下一个代码工作

TPL

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>

<a href="javascript:" class="req1">req1</a>
<a href="javascript:" class="req2">req2</a>
<br>

<form id="foo" action="" method="POST">{% csrf_token %}
    {{ form.as_p }}
    <input type="submit">
</form>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
    $(document).ready(function(){

        $('.req2').click(function(){
            var form1 = $.post( '', $('#foo').serialize(), function(data){console.log(data)} );
        })

        $('.req1').click(function(){
            var form1 = $.post( '', $('#foo').serialize(), function(data){console.log(data)} );
        })
    })
</script>
</body>
</html>

视图

from django import forms
from django.http import HttpResponse

from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect


class TestForm(forms.Form):
    test_field = forms.CharField()


@csrf_protect
def home(request):
    if request.method == 'POST':
        form = TestForm(request.POST)
        if form.is_valid():
            return HttpResponse('all ok')
    else: form = TestForm()

    return render(request,
        'page.html',
            {
            'form': form,
             },
    )

答案 1 :(得分:0)

问题解决了 - 我错过了负责ajax调用的js脚本在beforeSend函数中的表单输入(包括csrf标记)上设置'disabled'属性这一事实 - 这些禁用的attrs不会在POST中发送。 / p>