Как использовать защиту от CSRF в Django
Чтобы воспользоваться защитой от CSRF в ваших представлениях, выполните следующие шаги:
-
Промежуточное ПО CSRF активировано по умолчанию в настройке
MIDDLEWARE. Если вы переопределяете эту настройку, помните, что'django.middleware.csrf.CsrfViewMiddleware'должно идти перед любым промежуточным ПО представления, которое предполагает, что атаки CSRF были обработаны.Если вы отключили его, что не рекомендуется, вы можете использовать
csrf_protect()для отдельных представлений, которые вы хотите защитить (см. ниже). -
В любом шаблоне, который использует форму POST, используйте тег
csrf_tokenвнутри элемента<form>, если форма предназначена для внутреннего URL-адреса, например:<form method="post">{% csrf_token %}Этого не следует делать для форм POST, которые обращаются к внешним URL-адресам, поскольку это приведет к утечке маркера CSRF, что приведет к уязвимости.
- В соответствующих функциях представления убедитесь, что используется
RequestContextдля отображения ответа, чтобы{% csrf_token %}работало правильно. Если вы используете функциюrender(), общие представления или приложения contrib, вы уже защищены, поскольку все они используютRequestContext.
Использование защиты от CSRF с AJAX
Хотя описанный выше метод может использоваться для AJAX-запросов POST, он имеет некоторые неудобства: вы должны помнить о передаче маркера CSRF в качестве данных POST с каждым запросом POST. По этой причине существует альтернативный метод: для каждого XMLHttpRequest установите пользовательский заголовок X-CSRFToken (как указано в настройке CSRF_HEADER_NAME) в значение маркера CSRF. Это часто проще, поскольку многие фреймворки JavaScript предоставляют хуки, которые позволяют устанавливать заголовки для каждого запроса.
Сначала вы должны получить маркер CSRF. Как это сделать, зависит от того, включены ли настройки CSRF_USE_SESSIONS и CSRF_COOKIE_HTTPONLY.
Установка маркера в AJAX-запросе
Наконец, вам нужно установить заголовок в вашем AJAX-запросе. Используя API fetch():
const request = new Request(
/* URL */,
{
method: 'POST',
headers: {'X-CSRFToken': csrftoken},
mode: 'same-origin' // Do not send CSRF token to another domain.
}
);
fetch(request).then(function(response) {
// ...
});
Использование защиты от CSRF в шаблонах Jinja2
Бэкэнд шаблонов Django Jinja2 добавляет {{ csrf_input }} в контекст всех шаблонов, что эквивалентно {% csrf_token %} в языке шаблонов Django. Например:
<form method="post">{{ csrf_input }}
Использование метода декоратора
Вместо добавления CsrfViewMiddleware в качестве общей защиты, вы можете использовать декоратор csrf_protect(), который имеет точно такую же функциональность, для отдельных представлений, которым требуется защита. Он должен использоваться как в представлениях, которые вставляют маркер CSRF в вывод, так и в тех, которые принимают данные формы POST. (Это часто одна и та же функция представления, но не всегда).
Использование самого декоратора не рекомендуется, поскольку, если вы забудете его использовать, у вас будет брешь в безопасности. Стратегия «пояса и подтяжек» — использование обоих — хороша и будет иметь минимальные накладные расходы.
Обработка отклоненных запросов
По умолчанию пользователю отправляется ответ «403 Forbidden», если входящий запрос не проходит проверки, выполняемые CsrfViewMiddleware. Это обычно должно наблюдаться только тогда, когда существует подлинная межсайтовая подделка запроса или когда из-за ошибки программирования маркер CSRF не был включен в форму POST.
Однако страница ошибки не очень удобна, поэтому вы можете захотеть предоставить свое собственное представление для обработки этого условия. Для этого установите настройку CSRF_FAILURE_VIEW.
Сбои CSRF регистрируются как предупреждения в журнале django.security.csrf.
Использование защиты от CSRF с кэшированием
Если тег шаблона csrf_token используется шаблоном (или функция get_token вызывается каким-либо другим способом), CsrfViewMiddleware добавит cookie и заголовок Vary: Cookie в ответ. Это означает, что промежуточное ПО будет хорошо работать с промежуточным ПО кэша, если оно используется по инструкции (UpdateCacheMiddleware идет перед всеми другими промежуточными ПО).
Однако, если вы используете декораторы кэша для отдельных представлений, промежуточное ПО CSRF еще не сможет установить заголовок Vary или cookie CSRF, и ответ будет кэширован без ни одного из них. В этом случае для любых представлений, которым потребуется вставка маркера CSRF, вы должны сначала использовать декоратор django.views.decorators.csrf.csrf_protect():
from django.views.decorators.cache import cache_page from django.views.decorators.csrf import csrf_protect @cache_page(60 * 15) @csrf_protect def my_view(request): ...
Если вы используете представления на основе классов, вы можете обратиться к Декорирование представлений на основе классов.
Тестирование и защита от CSRF
CsrfViewMiddleware обычно будет серьезным препятствием для тестирования функций представления из-за необходимости маркера CSRF, который должен отправляться с каждым запросом POST. По этой причине HTTP-клиент Django для тестов был изменен для установки флага на запросы, которые ослабляют промежуточное ПО и декоратор csrf_protect, так что они больше не отклоняют запросы. Во всех остальных отношениях (например, отправка cookie и т. д.) они ведут себя одинаково.
Если по какой-либо причине вы хотите, чтобы тестовый клиент выполнял проверки CSRF, вы можете создать экземпляр тестового клиента, который применяет проверки CSRF:
>>> from django.test import Client >>> csrf_client = Client(enforce_csrf_checks=True)
Особые случаи
Определенные представления могут иметь необычные требования, которые означают, что они не соответствуют обычной схеме, предполагаемой здесь. Ряд утилит может быть полезен в этих ситуациях. Сценарии, в которых они могут потребоваться, описаны в следующем разделе.
Отключение защиты от CSRF только для нескольких представлений
Большинству представлений требуется защита от CSRF, но некоторым нет.
Решение: вместо отключения промежуточного ПО и применения csrf_protect ко всем представлениям, которым это необходимо, включите промежуточное ПО и используйте csrf_exempt().
Установка маркера, когда CsrfViewMiddleware.process_view() не используется
Есть случаи, когда CsrfViewMiddleware.process_view может не запускаться до запуска вашего представления — например, обработчики 404 и 500 —, но вам все еще нужен маркер CSRF в форме.
Решение: используйте requires_csrf_token()
Включение маркера CSRF в незащищенное представление
Могут быть некоторые представления, которые не защищены и были освобождены от csrf_exempt, но все еще должны включать маркер CSRF.
Решение: используйте csrf_exempt(), за которым следует requires_csrf_token(). (т. е. requires_csrf_token должен быть самым внутренним декоратором).
Защита представления только для одного пути
Представлению требуется защита от CSRF только при одном наборе условий, и в остальное время она не должна быть активна.
Решение: используйте csrf_exempt() для всей функции представления и csrf_protect() для пути внутри нее, которому требуется защита. Пример:
from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_exempt
def my_view(request):
@csrf_protect
def protected_path(request):
do_something()
if some_condition():
return protected_path(request)
else:
do_something_else()
Защита страницы, которая использует AJAX без HTML-формы
Страница делает запрос POST через AJAX, и на странице нет HTML-формы с csrf_token, которая привела бы к отправке необходимых cookie CSRF.
Решение: используйте ensure_csrf_cookie() в представлении, которое отправляет страницу.
Защита от CSRF в многоразовых приложениях
Поскольку разработчик может отключить CsrfViewMiddleware, все соответствующие представления в приложениях contrib используют декоратор csrf_protect для обеспечения безопасности этих приложений от CSRF. Разработчикам других многоразовых приложений, желающим получить те же гарантии, также рекомендуется использовать декоратор csrf_protect для своих представлений.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.2/howto/csrf/