Сбой проверки CSRF в Django с помощью запроса Ajax POST - PullRequest
169 голосов
/ 24 февраля 2011

Я мог бы помочь с соблюдением механизма защиты 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, и оно действительно заполнено некоторыми данными. Я не уверен, как проверить правильность токена, но я воодушевлен тем, что он что-то находит и отправляет.

Но Django все еще отвергает мой пост AJAX.

Вот мой JavaScript:

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

Вот ошибка, которую я вижу от Джанго:

[23 февраля 2011 г. 22:08:29] "POST / memorize / HTTP / 1.1" 403 2332

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

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

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

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

Ответы [ 18 ]

2 голосов
/ 04 мая 2017

вы можете вставить этот 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>
2 голосов
/ 06 мая 2011

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

С уважением,

Хиро

1 голос
/ 22 августа 2017

Если кто-то борется с 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/

1 голос
/ 21 июля 2017

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

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

2В моем случае для settings.CSRF_HEADER_NAME было установлено значение «HTTP_X_CSRFTOKEN», и мой AJAX-вызов отправлял заголовок с именем «HTTP_X_CSRF_TOKEN», поэтому все не работало.Я мог бы либо изменить его в вызове AJAX, либо в настройке django.

3) Если вы решите изменить его на стороне сервера, найдите место установки django и добавьте точку останова в csrf middleware .f вывы используете 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 правильно получен из запроса. META

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

1 голос
/ 19 апреля 2016

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

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

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

0 голосов
/ 09 августа 2018

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

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

$.ajax({
            type: 'POST',
            url: somepathname + "do_it/",
            data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
            success: function() {
                console.log("Success!");
            }
        })
0 голосов
/ 19 декабря 2017

Вот менее подробное решение, предоставленное 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/

0 голосов
/ 21 декабря 2015

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

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

# uwsgi_param             UWSGI_SCHEME    https;
# uwsgi_pass_header       X_FORWARDED_PROTO;
...