Ошибка проверки Django CSRF с запросом Ajax POST



я мог бы использовать некоторую помощь в соответствии с механизмом защиты CSRF Django через мой пост AJAX. Я следовал указаниям здесь:



http://docs.djangoproject.com/en/dev/ref/contrib/csrf/



Я скопировал пример кода AJAX, который они имеют на этой странице точно:



http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax



я поставил предупреждение печать содержимого getCookie('csrftoken') до xhr.setRequestHeader звонка и его действительно заполняется некоторыми данными. Я не уверен, как проверить правильность маркера, но я рад, что он находит и отправляет что-то.



но Джанго все еще отвергает мой пост AJAX.



вот мой JavaScript:



$.post("/memorize/", data, function (result) {
if (result != "failure") {
get_random_card();
}
else {
alert("Failed to save card data.");
}
});


вот ошибка, которую я вижу от Django:




[23 / Feb / 2011 22: 08: 29] "POST /memorize/ HTTP/1.1" 403 2332




Я уверен, что я что-то упускаю, и, может быть, это просто, но я не знаю, что это такое. Я искал вокруг так и увидел некоторую информацию о выключении проверки CSRF для моего просмотра через csrf_exempt декоратор, но я нахожу это непривлекательным. Я пробовал это, и это работает, но я бы предпочел, чтобы мой пост работал так, как Джанго был разработан, чтобы ожидать его, если это возможно.



на всякий случай это полезно, вот суть того, что делает мой взгляд:



def myview(request):

profile = request.user.profile

if request.method == 'POST':
"""
Process the post...
"""
return HttpResponseRedirect('/memorize/')
else: # request.method == 'GET'

ajax = request.GET.has_key('ajax')

"""
Some irrelevent code...
"""

if ajax:
response = HttpResponse()
profile.get_stack_json(response)
return response
else:
"""
Get data to send along with the content of the page.
"""

return render_to_response('memorize/memorize.html',
""" My data """
context_instance=RequestContext(request))


Спасибо за ваши ответы!

1138   18  

18 ответов:

реальное решение

хорошо, мне удалось отследить проблему. Он лежит в JavaScript (как я предложил ниже) код.

что вам нужно, это:

$.ajaxSetup({ 
     beforeSend: function(xhr, settings) {
         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;
         }
         if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
             // Only send the token to relative URLs i.e. locally.
             xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
         }
     } 
});

вместо кода, опубликованного в официальных документах: http://docs.djangoproject.com/en/1.2/ref/contrib/csrf/#ajax

рабочий код, происходит от этой записи Django: http://www.djangoproject.com/weblog/2011/feb/08/security/

таким образом, общее решение: "используйте обработчик ajaxSetup вместо обработчика ajaxSend". Я не знаю, почему это работает. Но это работает для меня :)

предыдущий пост (без ответа)

Я испытываю ту же проблему на самом деле.

это происходит после обновления до Django 1.2.5 - не было ошибок с запросами AJAX POST в Django 1.2.4 (AJAX не был защищен в в любом случае, но это сработало просто отлично).

как и OP, я попробовал фрагмент JavaScript, опубликованный в документации Django. Я использую jQuery 1.5. Я также использую "Джанго.промежуточное программное обеспечение.CSRF-атаку.CsrfViewMiddleware " middleware.

Я попытался следовать коду промежуточного программного обеспечения, и я знаю, что он не работает на этом:

request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')

а то

if request_csrf_token != csrf_token:
    return self._reject(request, REASON_BAD_TOKEN)

это" если "верно, потому что" request_csrf_token " пуст.

в основном это означает, что заголовок не ставить. Так что есть что-то не так с этой строкой JS:

xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));

?

Я надеюсь, что предоставленные детали помогут нам в решении этого вопроса:)

Если вы используете $.ajax функция, вы можете просто добавить csrf токен в теле данных:

$.ajax({
    data: {
        somedata: 'somedata',
        moredata: 'moredata',
        csrfmiddlewaretoken: '{{ csrf_token }}'
    },

добавьте эту строку в свой код jQuery:

$.ajaxSetup({
  data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});

и сделал.

проблема в том, что django ожидает, что значение из файла cookie будет передано обратно как часть данных формы. Код из предыдущего ответа получает javascript, чтобы выследить значение cookie и поместить его в данные формы. Это прекрасный способ сделать это с технической точки зрения, но это выглядит немного многословен.

в прошлом я делал это более просто, получая javascript, чтобы поместить значение токена в данные post.

Если вы используете {% csrf_token %} в вашем шаблоне вы получите скрытое поле формы, которое несет значение. Но, если вы используете {{ csrf_token }}, вы просто получите голое значение токена, поэтому вы можете использовать это в javascript следующим образом....

csrf_token = "{{ csrf_token }}";

затем вы можете включить это, с требуемым именем ключа в хэш, который вы затем отправляете в качестве данных для вызова ajax.

The {% csrf_token %} поместите в HTML шаблоны внутри <form></form>

переводится примерно так:

<input type='hidden' name='csrfmiddlewaretoken' value='Sdgrw2HfynbFgPcZ5sjaoAI5zsMZ4wZR' />

так почему бы просто не grep его в вашем JS, как это:

token = $("#change_password-form").find('input[name=csrfmiddlewaretoken]').val()

а затем передать его, например, делать какой-то пост, например:

$.post( "/panel/change_password/", {foo: bar, csrfmiddlewaretoken: token}, function(data){
    console.log(data);
});

Если ваша форма публикуется правильно в Django без JS, вы должны иметь возможность постепенно улучшать ее с помощью ajax без взлома или беспорядочной передачи токена csrf. Просто сериализуйте всю форму, и это автоматически заберет все ваши поля формы в том числе скрытое поле csrf:

$('#myForm').submit(function(){
    var action = $(this).attr('action');
    var that = $(this);
    $.ajax({
        url: action,
        type: 'POST',
        data: that.serialize()
        ,success: function(data){
            console.log('Success!');
        }
    });
    return false;
});

Я проверил это с Django 1.3+ и jQuery 1.5+. Очевидно, что это будет работать для любой HTML-формы, а не только для приложений Django.

не-jquery ответ:

var csrfcookie = function() {
    var cookieValue = null,
        name = 'csrftoken';
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
};

использование:

var request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.setRequestHeader('X-CSRFToken', csrfcookie());
request.onload = callback;
request.send(data);

принятый ответ, скорее всего, отвлекающий маневр. Разница между Django 1.2.4 и 1.2.5 была требованием для токена CSRF для запросов AJAX.

Я столкнулся с этой проблемой на Django 1.3, и это было вызвано тем, что файл cookie CSRF не установлен в первую очередь. Django не будет устанавливать куки, если это не нужно. Таким образом, исключительно или сильно ajax-сайт, работающий на Django 1.2.4, потенциально никогда не отправил бы токен клиенту, а затем обновление требование маркера вызвало бы 403 ошибки.

идеальное решение здесь: http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#page-uses-ajax-without-any-html-form
но вам придется подождать 1.4, если это не просто документация догоняет код

Edit

обратите внимание также, что более поздние документы Django отмечают ошибку в jQuery 1.5, поэтому убедитесь, что вы используете 1.5.1 или более позднюю версию с предложенным Django код: http://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#ajax

используйте Firefox с Firebug. Откройте вкладку "консоль" при запуске запроса ajax. С DEBUG=True вы получаете хорошую страницу ошибок django в качестве ответа, и вы даже можете увидеть отображаемый html ответа ajax на вкладке консоли.

тогда вы будете знать, в чем ошибка.

Я только что столкнулся с немного другой, но похожей ситуацией. Не на 100% уверен, что это будет решение для вашего случая, но я решил проблему для Django 1.3, установив параметр POST "csrfmiddlewaretoken" с правильной строкой значения cookie, которая обычно возвращается в виде вашего домашнего HTML системой шаблонов Django с тегом " {%csrf_token%}". Я не пробовал на старом Django, просто произошло и решилось на Django1.3. Моя проблема заключалась в том, что первый запрос был отправлен через Ajax из формы было успешно сделано, но вторая попытка из того же самого из failed, привела к состоянию 403, даже если заголовок "X-CSRFToken" правильно помещен со значением токена CSRF, а также в случае первой попытки. Надеюсь, это поможет.

с уважением,

Хиро

вы можете вставить этот js в свой html-файл, помните, что поместите его перед другой функцией js

<script>
  // using jQuery
  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;
  }

  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }

  $(document).ready(function() {
    var csrftoken = getCookie('csrftoken');
    $.ajaxSetup({
      beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
  });
</script>

кажется, никто не упоминал, как это сделать в чистом JS с помощью и {{ csrf_token }}, Так вот простое решение, где вам не нужно искать через куки или дом:

var xhttp = new XMLHttpRequest();
xhttp.open("POST", url, true);
xhttp.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
xhttp.send();

один токен CSRF присваивается каждому сеансу (т. е. каждый раз, когда вы входите в систему). Поэтому, прежде чем вы захотите получить некоторые данные, введенные пользователем, и отправить их как вызов ajax некоторой функции, защищенной csrf_protect decorator, попробуйте найти функции, которые вызываются, прежде чем вы получите эти данные от пользователя. Например, какой-то шаблон должен быть визуализирован, на котором ваш пользователь вводит данные. Этот шаблон отображается некоторой функцией. В этой функции вы можете получить токен csrf в виде следует: csrf = запрос.COOKIES ['csrftoken'] Теперь передайте это значение csrf в контекстный словарь, против которого данный шаблон отображается. Теперь в этом шаблоне напишите эту строку: Теперь в вашей функции javascript, прежде чем сделать запрос ajax, напишите это: var csrf = $('#csrf').val () это выберет значение токена, переданного шаблону, и сохранит его в переменной csrf. Теперь при вызове ajax в ваших данных post также передайте это значение : "csrfmiddlewaretoken": csrf

Это работайте, даже если вы не реализуете формы django.

на самом деле, логика здесь такова : вам нужен токен, который вы можете получить из запроса. Поэтому вам просто нужно выяснить, что функция вызывается сразу после входа в систему. Как только у вас есть этот токен, либо сделайте еще один вызов ajax, чтобы получить его, либо передайте его в какой-либо шаблон, доступный вашему ajax.

для тех, кто сталкивается с этим и пытается отладить:

1) проверка django csrf (предполагая, что вы отправляете один) является здесь

2) в моем случае, settings.CSRF_HEADER_NAME было установлено значение ' HTTP_X_CSRFTOKEN 'и мой AJAX-вызов отправлял заголовок с именем' HTTP_X_CSRF_TOKEN', так что материал не работал. Я могу изменить его в AJAX-вызов, или установка Джанго.

3) Если вы решите изменить его на стороне сервера, найдите место установки django и бросьте точка останова в csrf middleware.если вы используете virtualenv, это будет что-то вроде: ~/.envs/my-project/lib/python2.7/site-packages/django/middleware/csrf.py

import ipdb; ipdb.set_trace() # breakpoint!!
if request_csrf_token == "":
    # Fall back to X-CSRFToken, to make things easier for AJAX,
    # and possible for PUT/DELETE.
    request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

затем, убедитесь, что csrf токен правильно получен из запроса.Мета

4) Если вам нужно изменить заголовок и т. д. - измените эту переменную в файле настроек

Если кто-то борется с axios, чтобы сделать эту работу, это помогло мне:

import axios from 'axios';

axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'

Источник:https://cbuelter.wordpress.com/2017/04/10/django-csrf-with-axios/

в моем случае проблема была с конфигурацией nginx, которую я скопировал с основного сервера на временный с отключением https, который не нужен на втором в этом процессе.

Я должен был прокомментировать эти две строки в конфигурации, чтобы заставить его работать снова:

# uwsgi_param             UWSGI_SCHEME    https;
# uwsgi_pass_header       X_FORWARDED_PROTO;

вот менее подробное решение, предоставленное Django:

<script type="text/javascript">
// using jQuery
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();

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

// Ajax call here
$.ajax({
    url:"{% url 'members:saveAccount' %}",
    data: fd,
    processData: false,
    contentType: false,
    type: 'POST',
    success: function(data) {
        alert(data);
        }
    });
</script>

Источник:https://docs.djangoproject.com/en/1.11/ref/csrf/

как это не указано нигде в текущих ответах, самое быстрое решение, если вы не врезать js в вашем шаблоне:

поставить <script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script> перед вашей ссылкой на скрипт.js файл в вашем шаблоне, а затем добавить csrfmiddlewaretoken в своем data словарь в вашем js-файле:

$.ajax({
            type: 'POST',
            url: somepathname + "do_it/",
            data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
            success: function() {
                console.log("Success!");
            }
        })

Comments

    Ничего не найдено.