Как использовать защиту от CSRF в Django

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

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

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

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

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

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

  3. В соответствующих функциях представления убедитесь, что 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 или куки 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):
    ...

Если вы используете представления на основе классов, вы можете обратиться к Decorating class-based views.

Тестирование и защита от CSRF

Декоратор CsrfViewMiddleware обычно сильно мешает тестированию функций представления из-за необходимости использования CSRF-токена, который должен быть отправлен с каждым POST-запросом. По этой причине HTTP-клиент Django для тестов был модифицирован для установки флага в запросах, который ослабляет промежуточное программное обеспечение и декоратор csrf_protect, так что они больше не отклоняют запросы. Во всех остальных отношениях (например, отправка cookies и т.д.) они ведут себя одинаково.

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

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

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

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

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