“CSRF令牌丢失或不正确”,同时通过AJAX在Django中发布参数

时间:2022-02-24 04:53:30

I try to post parameter like

我尝试像这样发布参数

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

However, Django return Forbidden 403. CSRF verification failed. Request aborted. I am using 'django.middleware.csrf.CsrfViewMiddleware' and couldn't find how I can prevent this problem without compromising security.

但是,Django返回了禁用的403。CSRF验证失败。请求中止。我使用“django.middleware.csrf。CsrfViewMiddleware'并且无法找到如何在不损害安全性的情况下防止这个问题的方法。

9 个解决方案

#1


76  

You can make AJAX post request in two different ways:

AJAX post请求有两种不同的方式:

  1. To tell your view not to check the csrf token. This can be done by using decorator @csrf_exempt, like this:

    告诉您的视图不要检查csrf令牌。这可以通过decorator @ csrf_豁免权来实现,如下所示:

    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def your_view_name(request):
        ...
    
  2. To embed a csrf token in each AJAX request, for jQuery it may be:

    要在每个AJAX请求中嵌入csrf令牌,jQuery可以是:

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

    Where the getCookie function retrieves csrf token from cookies. I use the following implementation:

    getCookie函数从cookie中检索csrf令牌。我使用以下实现:

    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 "";
     }
    

    Also, jQuery has a plugin for accessing cookies, something like that:

    此外,jQuery还有一个用于访问cookie的插件,类似于:

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

#2


33  

The simplest way I have found is to include the {{csrf_token}} value in the data:

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

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

#3


22  

It took me a while to understand what to do with the code that Daniel posted. But actually all you have to do is paste it at the beginning of the javascript file.

我花了一段时间才明白了丹尼尔发布的代码该怎么做。但是实际上,您所要做的就是在javascript文件的开头粘贴它。

For me, the best solution so far is:

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

  1. Create a csrf.js file

    创建一个csrf。js文件

  2. Paste the code in the csrf.js file

    在csrf中粘贴代码。js文件

  3. Reference the code in the template you need it

    在需要的模板中引用代码

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

Notice that STATIC_PREFIX/js/csrf.js points to my file. I am actually loading the STATIC_PREFIX variable with {% get_static_prefix as STATIC_PREFIX %}.

请注意,STATIC_PREFIX / js / csrf。js指向我的文件。实际上,我正在加载带有{% get_static_前缀为STATIC_PREFIX %}的STATIC_PREFIX变量。


Advanced tip: if you are using templates and have something like base.html where you extend from, then you can just reference the script from there and you don't have to worry anymore in there rest of your files. As far as I understand, this shouldn't represent any security issue either.

高级提示:如果您正在使用模板,并且有一些类似于base的东西。扩展到html的地方,然后你可以从那里引用脚本,你就不用再担心其他文件了。据我所知,这也不代表任何安全问题。

#4


4  

I got the same issue yesterday and thought it would help people if there were a simple way to handle it, so I wrote a jQuery plugin for that: jquery.djangocsrf. Instead of adding the CSRF token in every request, it hooks itself on the AjaxSend jQuery event and adds the client cookie in a header.

昨天我也遇到了同样的问题,我认为如果有一种简单的方法可以解决这个问题,那么它会对人们有所帮助,所以我为此写了一个jQuery插件:jquery.djangocsrf。它没有在每个请求中添加CSRF令牌,而是将自己挂接到AjaxSend jQuery事件上,并将客户端cookie添加到header中。

Here’s how to use it:

下面是如何使用它的方法:

1- include it:

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- enable it in your code:

2-在您的代码中启用它:

$.djangocsrf( "enable" );

Django always add the token in a cookie if your template uses {% csrf_token %}. To ensure it always adds it even if you don’t use the special tag in your template, use the @ensure_csrf_cookie decorator:

如果模板使用{% csrf_token %}, Django总是在cookie中添加该令牌。为了确保它总是添加它,即使您不使用模板中的特殊标记,请使用@ensure_csrf_cookie decorator:

from django.views.decorators.csrf import ensure_csrf_cookie

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

Note: I’m using Django 1.6.2.

注意:我使用的是Django 1.6.2。

#5


4  

Thank you everyone for all the answers. I am using Django 1.5.1. I'm a little late to the party, but here goes.

谢谢大家的回答。我使用的是Django 1.5.1。我去参加聚会有点晚了,但我来了。

I found the link to the Django project to be very useful, but I didn't really want to have to include the extra JavaScript code every time I wanted to make an Ajax call.

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

I like jerrykan's response as it is very succinct and only adds one line to an otherwise normal Ajax call. In response to the comments below his comment regarding situations when Django template tags are unavailable, how about loading up the csrfmiddlewaretoken from the DOM?

我喜欢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); } 
});

EDIT March 2016

编辑2016年3月

My approach to this issue over the past few years has changed. I add the code below (from the Django docs) to a main.js file and load it on every page. Once done, you shouldn't need to worry about the CSRF token with ajax again.

过去几年,我对这个问题的态度发生了变化。我将下面的代码(来自Django文档)添加到一个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');

#6


3  

For lack of a straight forward answer, you just have to add the header X-CSRFToken to the ajax request which is in the cookie csrftoken. JQuery doesn't do cookies (for some reason) without a plugin so:

由于没有直接的答案,您只需将header X-CSRFToken添加到cookie csrftoken中的ajax请求中。JQuery在没有插件的情况下不会做cookie(出于某种原因),所以:

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

and the minimal code change is:

最小的代码更改是:

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

#7


3  

Simple and short

简单和短

$.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

文档

#8


2  

Include x-csrftoken header in request:

在请求中包含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',

});

#9


0  

If, after reading other answers, someone is still struggling please try this:

如果在阅读了其他答案后,有人仍在苦苦挣扎,请尝试以下方法:

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

#1


76  

You can make AJAX post request in two different ways:

AJAX post请求有两种不同的方式:

  1. To tell your view not to check the csrf token. This can be done by using decorator @csrf_exempt, like this:

    告诉您的视图不要检查csrf令牌。这可以通过decorator @ csrf_豁免权来实现,如下所示:

    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def your_view_name(request):
        ...
    
  2. To embed a csrf token in each AJAX request, for jQuery it may be:

    要在每个AJAX请求中嵌入csrf令牌,jQuery可以是:

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

    Where the getCookie function retrieves csrf token from cookies. I use the following implementation:

    getCookie函数从cookie中检索csrf令牌。我使用以下实现:

    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 "";
     }
    

    Also, jQuery has a plugin for accessing cookies, something like that:

    此外,jQuery还有一个用于访问cookie的插件,类似于:

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

#2


33  

The simplest way I have found is to include the {{csrf_token}} value in the data:

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

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

#3


22  

It took me a while to understand what to do with the code that Daniel posted. But actually all you have to do is paste it at the beginning of the javascript file.

我花了一段时间才明白了丹尼尔发布的代码该怎么做。但是实际上,您所要做的就是在javascript文件的开头粘贴它。

For me, the best solution so far is:

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

  1. Create a csrf.js file

    创建一个csrf。js文件

  2. Paste the code in the csrf.js file

    在csrf中粘贴代码。js文件

  3. Reference the code in the template you need it

    在需要的模板中引用代码

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

Notice that STATIC_PREFIX/js/csrf.js points to my file. I am actually loading the STATIC_PREFIX variable with {% get_static_prefix as STATIC_PREFIX %}.

请注意,STATIC_PREFIX / js / csrf。js指向我的文件。实际上,我正在加载带有{% get_static_前缀为STATIC_PREFIX %}的STATIC_PREFIX变量。


Advanced tip: if you are using templates and have something like base.html where you extend from, then you can just reference the script from there and you don't have to worry anymore in there rest of your files. As far as I understand, this shouldn't represent any security issue either.

高级提示:如果您正在使用模板,并且有一些类似于base的东西。扩展到html的地方,然后你可以从那里引用脚本,你就不用再担心其他文件了。据我所知,这也不代表任何安全问题。

#4


4  

I got the same issue yesterday and thought it would help people if there were a simple way to handle it, so I wrote a jQuery plugin for that: jquery.djangocsrf. Instead of adding the CSRF token in every request, it hooks itself on the AjaxSend jQuery event and adds the client cookie in a header.

昨天我也遇到了同样的问题,我认为如果有一种简单的方法可以解决这个问题,那么它会对人们有所帮助,所以我为此写了一个jQuery插件:jquery.djangocsrf。它没有在每个请求中添加CSRF令牌,而是将自己挂接到AjaxSend jQuery事件上,并将客户端cookie添加到header中。

Here’s how to use it:

下面是如何使用它的方法:

1- include it:

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- enable it in your code:

2-在您的代码中启用它:

$.djangocsrf( "enable" );

Django always add the token in a cookie if your template uses {% csrf_token %}. To ensure it always adds it even if you don’t use the special tag in your template, use the @ensure_csrf_cookie decorator:

如果模板使用{% csrf_token %}, Django总是在cookie中添加该令牌。为了确保它总是添加它,即使您不使用模板中的特殊标记,请使用@ensure_csrf_cookie decorator:

from django.views.decorators.csrf import ensure_csrf_cookie

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

Note: I’m using Django 1.6.2.

注意:我使用的是Django 1.6.2。

#5


4  

Thank you everyone for all the answers. I am using Django 1.5.1. I'm a little late to the party, but here goes.

谢谢大家的回答。我使用的是Django 1.5.1。我去参加聚会有点晚了,但我来了。

I found the link to the Django project to be very useful, but I didn't really want to have to include the extra JavaScript code every time I wanted to make an Ajax call.

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

I like jerrykan's response as it is very succinct and only adds one line to an otherwise normal Ajax call. In response to the comments below his comment regarding situations when Django template tags are unavailable, how about loading up the csrfmiddlewaretoken from the DOM?

我喜欢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); } 
});

EDIT March 2016

编辑2016年3月

My approach to this issue over the past few years has changed. I add the code below (from the Django docs) to a main.js file and load it on every page. Once done, you shouldn't need to worry about the CSRF token with ajax again.

过去几年,我对这个问题的态度发生了变化。我将下面的代码(来自Django文档)添加到一个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');

#6


3  

For lack of a straight forward answer, you just have to add the header X-CSRFToken to the ajax request which is in the cookie csrftoken. JQuery doesn't do cookies (for some reason) without a plugin so:

由于没有直接的答案,您只需将header X-CSRFToken添加到cookie csrftoken中的ajax请求中。JQuery在没有插件的情况下不会做cookie(出于某种原因),所以:

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

and the minimal code change is:

最小的代码更改是:

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

#7


3  

Simple and short

简单和短

$.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

文档

#8


2  

Include x-csrftoken header in request:

在请求中包含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',

});

#9


0  

If, after reading other answers, someone is still struggling please try this:

如果在阅读了其他答案后,有人仍在苦苦挣扎,请尝试以下方法:

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