【问题标题】:Django + jQuery: Why CSRF verification fails on multiple simultaneous requestsDjango + jQuery:为什么 CSRF 验证在多个同时请求上失败
【发布时间】:2012-07-17 12:41:49
【问题描述】:

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

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

【问题讨论】:

  • 如果您自己而不是与 ajax 提交同时进行,那么 jQuery 的“提交”是否有效?
  • 是你的ajax properly 发送POST。您能否提供确切的错误消息,因为在来源中我没有看到您的错误REASON_NO_REFERER = "Referer checking failed - no Referer." REASON_BAD_REFERER = "Referer checking failed - %s does not match %s." REASON_NO_CSRF_COOKIE = "CSRF cookie not set." REASON_BAD_TOKEN = "CSRF token missing or incorrect."
  • @Anentropic:是的,提交单独完成时有效。
  • @b1-:确切的消息是:CSRF 令牌丢失或不正确。
  • @fjern 在我的回答中很少研究。使用 PyCharm 进行调试

标签: jquery django csrf django-csrf


【解决方案1】:

我认为你的代码有问题。只需阅读 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 和 cookie(发送浏览器)不相等


下一个代码工作

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,
             },
    )

【讨论】:

    【解决方案2】:

    问题已解决 - 我错过了这样一个事实,即负责 ajax 调用的 js 脚本在 beforeSend 函数中的表单输入(包括 csrf 令牌)上设置了“禁用”属性 - 此类禁用的属性不会在 POST 中发送。

    【讨论】:

    • 怎么样?你是怎么解决的?帮助别人!
    猜你喜欢
    • 2012-03-30
    • 1970-01-01
    • 2012-12-07
    • 2015-03-08
    • 1970-01-01
    • 1970-01-01
    • 2014-02-03
    • 2016-05-29
    相关资源
    最近更新 更多