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-токен, должны вручную установить заголовок.