2011-06-28 194 views
46

之后的参数我尝试发布的参数一样“CSRF令牌丢失或不正确”,而通过AJAX在Django

jQuery.ajax(
     { 
      'type': 'POST', 
      'url': url, 
      'contentType': 'application/json', 
      'data': "{content:'xxx'}", 
      'dataType': 'json', 
      'success': rateReviewResult 
     } 
    ); 

然而,Django的返回Forbidden 403. CSRF verification failed. Request aborted. 我使用'django.middleware.csrf.CsrfViewMiddleware',但没有找到我怎么能防止这种问题而不影响安全性。

+0

http://stackoverflow.com/questions/5100539/django-csrf-check-failing-with-an-ajax-post-request –

回答

75

你可以让AJAX POST请求以两种不同的方式:

  1. 要告诉你的看法不检查CSRF令牌。这可以通过使用装饰@csrf_exempt来完成,像这样:

    from django.views.decorators.csrf import csrf_exempt 
    
    @csrf_exempt 
    def your_view_name(request): 
        ... 
    
  2. 在每个AJAX请求嵌入一个CSRF令牌,jQuery的可能:

    $(function() { 
        $.ajaxSetup({ 
         headers: { "X-CSRFToken": getCookie("csrftoken") } 
        }); 
    }); 
    

    getCookie函数检索CSRF令牌来自cookies。我用下面的实现:

    function getCookie(c_name) 
    { 
        if (document.cookie.length > 0) 
        { 
         c_start = document.cookie.indexOf(c_name + "="); 
         if (c_start != -1) 
         { 
          c_start = c_start + c_name.length + 1; 
          c_end = document.cookie.indexOf(";", c_start); 
          if (c_end == -1) c_end = document.cookie.length; 
          return unescape(document.cookie.substring(c_start,c_end)); 
         } 
        } 
        return ""; 
    } 
    

    此外,jQuery的has a plugin访问饼干,这样的事情:

    // set cookie 
    $.cookie('cookiename', 'cookievalue');<br> 
    // read cookie 
    var myCookie = $.cookie('cookiename');<br> 
    // delete cookie 
    $.cookie('cookiename', null); 
    
+2

重要的是要注意它是'X-CSRFToken'而不是'X -CSRF-Token'也是常用的 – shangxiao

+2

使用'csrf_exempt'修饰器可能会导致安全问题,因为中间件保护将被禁用。 –

31

我发现最简单的方法是包含在数据中的{{csrf_token}}值:

jQuery.ajax(
    { 
     'type': 'POST', 
     'url': url, 
     'contentType': 'application/json', 
     'data': { 
      'content': 'xxx', 
      'csrfmiddlewaretoken': '{{ csrf_token }}', 
     }, 
     'dataType': 'json', 
     'success': rateReviewResult 
    } 
); 
+4

如果您的JavaScript未由Django处理,该怎么办?猜猜你真的会爬上小溪。 –

+3

最初的问题表明他们使用的是'django.middleware.csrf.CsrfViewMiddleware',Django正在返回错误,所以我认为假设Django正在处理ajax请求是非常安全的。 – jerrykan

+5

问题是,Django不是模仿JS,只是HTML视图。 –

22

我花了一段时间才明白如何处理Daniel发布的。但实际上你所要做的就是将它粘贴到JavaScript文件的开头。

对我来说,最好的解决办法,到目前为止是:

  1. csrf.js文件

  2. 参考模板,你需要它的代码创建一个csrf.js文件

  3. 粘贴the code

    <script type="text/javascript" src="{{ STATIC_PREFIX }}js/csrf.js"></script> 
    

请注意,STATIC_PREFIX/js/csrf.js指向我的文件。我实际上是用{% get_static_prefix as STATIC_PREFIX %}加载STATIC_PREFIX变量。


高级提示:如果您正在使用的模板,并有你来自哪里,延长像base.html,那么你可以从那里引用脚本,你不必在那里休息了您的后顾之忧文件。据我了解,这也不应该代表任何安全问题。

+3

这节省了我几个小时的时间。简单和Pythonic的方式从Django文档。 – Pratyush

+0

通过“代码”你是指绿色背景中的每一个字符?我复制粘贴,并按照你的说法,但仍然得到403禁止错误。也许事情已经改变了? – Philip007

+0

@ Philip007,是的,绿色的背景。他们更改了[Django 1.5]的文档(https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/),但是在结果代码中我看不到任何实际的差异。他们只是给出了更长的解释和使用jQuery的选项。 –

4

谢谢大家的所有答案。我正在使用Django 1.5.1。我对派对有点迟到,但这里走了。

我发现指向Django project的链接非常有用,但我并不想每次想要进行Ajax调用时都需要包含额外的JavaScript代码。

我喜欢jerrykan的回答,因为它非常简洁,只增加一行到其他正常的Ajax调用。为了回应下面有关Django模板标签不可用时的情况的评论,请参考如何从DOM中加载csrfmiddlewaretoken?

var token = $('input[name="csrfmiddlewaretoken"]').prop('value'); 
jQuery.ajax({ 
    type: 'POST', 
    url: url, 
    data: { 'csrfmiddlewaretoken': token }, 
    dataType: 'json', 
    success: function(data) { console.log('Yippee! ' + data); } 
}); 

编辑2016年3月

我的方法对这一问题在过去几年中发生了变化。我将下面的代码(从Django docs)添加到main.js文件并将其加载到每个页面上。完成后,您不必再担心使用ajax的CSRF令牌。

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');

4

我昨天得到了同样的问题,并认为这将有助于人们如果有一个简单的方法来处理它,所以我写了一个jQuery插件为:jquery.djangocsrf。不是在每个请求中添加CSRF标记,而是将其自身绑定到AjaxSend jQuery事件上,并将客户端Cookie添加到标头中。

下面是如何使用它:

1 - 包括它:

<script src="path/to/jquery.js"></script> 
<script src="path/to/jquery.cookie.js"></script> 
<script src="path/to/jquery.djangocsrf.js"></script> 

2-启用它在你的代码:

$.djangocsrf("enable"); 

的Django随时添加令牌在cookie中,如果您的模板使用{% csrf_token %}。为了确保它总是添加它,即使你没有在你的模板中使用的特殊标记,使用@ensure_csrf_cookie装饰:

from django.views.decorators.csrf import ensure_csrf_cookie 

@ensure_csrf_cookie 
def my_view(request): 
    return render(request, 'mytemplate.html') 

注:我使用Django 1.6.2。

2

包括在请求x-csrftoken头:

var token = $('input[name="csrfmiddlewaretoken"]').prop('value'); 
jQuery.ajax({ 
    type: 'POST', 
    url: url, 
    beforeSend : function(jqXHR, settings) { 
     jqXHR.setRequestHeader("x-csrftoken", get_the_csrf_token_from_cookie()); 
    }, 
    data: data, 
    dataType: 'json', 

}); 
0

如果在阅读其他的答案后,有人还在挣扎,请尝试这个办法:

$.ajax({ 
      type: "POST", 
      beforeSend: function (request) 
      { 
       request.setRequestHeader("X-CSRF-TOKEN", "${_csrf.token}"); 
      }, 
      url: servlet_path, 
      data : data, 
      success : function(result) { 
      console.log("Success!"); 
    } 
}); 
+0

我无法按照此处所述使其工作。有任何想法吗?它显示为'beforeSend'属性不能正确地抓取令牌......? – natureminded

3

由于缺乏一个直接的答案,你就必须将标头X-CSRFToken添加到cookie csrftoken中的ajax请求。jQuery也没有a plugin这样做饼干(出于某种原因):

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script> 

和最少的代码改变是:

$.ajax({ 
    headers: { "X-CSRFToken": $.cookie("csrftoken") }, 
    ... 
}); 
+0

千投票的人.....我总是想知道为什么人们不能做这样简单的答案! – NoobEditor

2

简单和短期

$.ajaxSetup({ 
    headers: { "X-CSRFToken": '{{csrf_token}}' } 
}); 

OR

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

docs

相关问题