2011-06-28 248 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

相關問題