• 3.1
  • 3.2
  • 5.0
  • Версия документации: 6.1

Как пользоваться системой защиты от CSRF в Django

Чтобы воспользоваться системой защиты от CSRF в ваших представлениях, проделайте следующие шаги:

  1. CSRF middleware можно активировать (а по-умолчанию оно должно быть активировано), указав его в списке MIDDLEWARE в настройках. Если вы переопределяете этот список, имейте в виду, что 'django.middleware.csrf.CsrfViewMiddleware' должно стоять перед любым middleware представления, чтобы отражение CSRF атак работало корректно.

    Если вы все же отключите его (что мы крайне не рекомендуем делать), вы можете использовать декоратор csrf_protect() на конкретных представлениях, которые вы хотите защитить (см. ниже).

  2. В любом шаблоне, которые использует POST форму, используйте тэг csrf_token внутри HTML элемента <form>:

    <form method="post">{% csrf_token %}
    

    Не нужно делать это для POST форм, таргетом которых является внешний URL, так как это может привести к утечке CSRF токена, что, в свою очередь, создаст уязвимость.

  3. Убедитесь, что в функциях представлений используется класс RequestContext для создания респонса, чтобы {% csrf_token %} работал корректно. Если вы используете render() общие представления, или приложения из библиотеки Django, все будет работать из коробки, потому что они используют RequestContext.

Использование CSRF защиты с AJAX

Несмотря на то, что указанным выше методом можно пользоваться при AJAX POST запросах, он несет ряд неудобств: Нужно помнить, что при каждом запросе нужно передавать CSRF токен в данных формы. По этой причине появился альтернативный метод: на каждый XMLHttpRequest установить заголовок X-CSRFToken (указывается настройкой CSRF_HEADER_NAME).Часто это сильно проще, так как многие JavaScript фреймворки предоставляют хуки, позволяющие добавлять HTTP заголовки к каждому запросу.

Для начала, нужно получить CSRF токен. Как это сделать, зависит от того, установлены ли настройки CSRF_USE_SESSIONS and CSRF_COOKIE_HTTPONLY.

Установка токена в AJAX запросе

Наконец, вам понадобится установить HTTP заголовок для AJAX запроса с помощью fetch() API:

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

Бэкенд шаблона Jinja2 добавляет {{ csrf_input }} в контекст всех шаблонов, что является эквивалентом использованию {% csrf_token %} в шаблоне. К примеру:

<form method="post">{{ csrf_input }}

Использование декоратора

Вместо того, чтобы добавлять CsrfViewMiddleware в качестве тотальной защиты для всех запросов, вы можете использовать декоратор csrf_protect(), который делает то же самое, но только для тех представлений, где вам нужна эта защита. Его нужно использовать для обоих представлений: и для тех, где вы вставляете CSRF токен, и для тех, что принимают вывод форм в POST запросах (Вы можете обрабатывать данные формы в том же представлении, но не обязательно).

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

Обработка отклоненных запросов

По-умолчанию, если запрос отклоняется после проверки CsrfViewMiddleware, пользователь получает ответ „403 Forbidden“. Обычно это происходит при реальной CSRF атаке или когда в результате ошибки CSRF токен не был добавлен в POST форму.

Страница ошибки в этом случае, будет не очень красивой, так что вам может понадобиться определить собственное представление для показа собственного шаблона. Для этого нужно в настройках указать CSRF_FAILURE_VIEW.

Логгером django.security.csrf CSRF ошибки записываются как предупреждения.

Использование CSRF защиты при кэшировании

Если тег csrf_token используется в шаблоне (или функция get_token вызывается каким-либо другим образом), CsrfViewMiddleware добавит куки и заголовок Vary: Cookie в ответ. Это означает, что CSRF middleware будет работать корректно в случае применения кэширования, если оно применено правильно (UpdateCacheMiddleware должно быть прописано раньше всех других middleware).

Однако, если вы ставите декораторы на конкретные функции представлений, CSRF middleware не сможет установить HTTP заголовок Vary или куки CSRF, и ответ сервера будет закэширован и без заголовка, и без куки. В этом случае, на таких функциях вам также необходимо устанавливать декоратор func: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 может создать проблемы при тестировании представлений (views), из-за необходимости отправлять CSRF токен с каждым POST запросом. По этой причине HTTP клиент Django для тестов был модифицирован таким образом, что он устанавливает определенный флаг в запросах и csrf_protect декораторе, чтобы они не отменяли такие запросы. Во всех остальных отношениях (к примеру, отправке кукис и т.д.), они будут работать так же, как и раньше.

Если, по какой-либо причине, вы хотите, чтобы тестовый клиент выполнял CSRF проверки, вы можете создать объект такого тестового клиента, выполняющего эту проверку:

>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)

Крайние случаи

Некоторые представления могут иметь необычные требования, и к ним будут неприменимы действия, описанные здесь. Тем не менее, есть определенные инструменты, которые могут быть полезны в таких ситуациях. Более подробное описание вы можете прочитать в следующем разделе.

Отключение CSRF защиты для отдельных представлений

Обычно представлениям нужна CSRF защита, но не всегда.

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

Защита представления только для одного URL

Такая ситуация: Представление нуждается в защите от 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, которая могла отправить CSRF-cookie.

Решение: используйте ensure_csrf_cookie() в представлении, которое обрабатывает запрос.

Защита CSRF-атак в отдельно используемых приложениях

Поскольку разработчик может отключить CsrfViewMiddleware, все соответствующие представления в приложениях contriиспользуют декоратор csrf_protect для обеспечения безопасности этих приложений от CSRF. Разработчикам других приложений, которые хотят получить те же гарантии, также рекомендуется использовать декоратор csrf_protect в своих представлениях.

Back to Top