Django AJAX: прохождение проверки формы CSFR без должного вложения токена. Почему?

У меня есть небольшой проект Django 5.1.1, в котором я использую AJAX-запрос для отправки данных формы. Я использую {% csrf_token %} и настроил прикрепление csrfToken формы к заголовку xhr.

Проблема: проверка CSFR проходит УСПЕШНО, даже когда xhr.setRequestHeader('X-CSRFToken', csrfToken); закомментирован. AJAX-запрос проходит и получает ответ. Сбой происходит только тогда, когда {% csrf_token %} отсутствует.

Насколько я понимаю, без формы csfrToken, прикрепленной к заголовку, она не должна работать. Что я здесь упускаю?

Упрощенный код:

<form id="form1" method="post" class="...">
 {% csrf_token %}

 <div>
  <label for="A" class=""></label>
  <input type="text" name="symbol" id="A" class="...">
 </div>

 <div>
   <button type="submit" id="submit-button"></button>
 </div>

</form>

document.getElementById('form1').addEventListener('submit', function(event) {
  event.preventDefault();

  const xhr = new XMLHttpRequest();
  const formData = new FormData(this);
  const csrfToken = this.querySelector('[name=csrfmiddlewaretoken]').value;

  xhr.open('POST', '/form-submit', true);
  // xhr.setRequestHeader('X-CSRFToken', csrfToken);
  xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  xhr.send(formData);
});
def index_view(request):

    return HttpResponse("", status=200)
MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

You are sending the form data, so then the header is not necessary, since the csrf token is in the form data. Indeed, the {% csrf_token %} template tag [Django-doc] translates to a hidden HTML input element, something like:

<input type="hidden" name="csrfmiddlewaretoken" value="---some-token---">

В этом элементе ввода нет ничего особенного. Это просто элемент HTML, как и любой другой.

Ваши JavaScript-функции кодируют всю форму, поэтому включает элемент с csrfmiddlewaretoken. Django пытается найти CSRF-токен в заголовке, и в POST-данных, и вот он в POST-данных.

Если вы удалите setHeader и {% csrf_token %}, он больше не будет работать.

Однако часто AJAX-запросы не кодируют данные формы, а просто получают их откуда-то еще, например, из data-… атрибутов HTML-элементов. Поэтому такие AJAX-запросы, которые, таким образом, не работают с формой, предоставляющей CSRF-токен, должны вручную установить заголовок.

Вернуться на верх