Spec-Zone.ru › Django 5.0

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

Чтобы воспользоваться защитой от 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.

Получение токена, если CSRF_USE_SESSIONS и CSRF_COOKIE_HTTPONLY False

Рекомендуемым источником токена является cookie csrftoken, который будет установлен, если вы включили защиту CSRF для своих представлений, как описано выше.

Cookie токена CSRF по умолчанию имеет имя csrftoken, но вы можете управлять именем cookie с помощью настройки CSRF_COOKIE_NAME.

Вы можете получить токен следующим образом:

function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
const csrftoken = getCookie('csrftoken');

Вышеприведенный код можно упростить, используя библиотеку JavaScript Cookie JavaScript Cookie library для замены getCookie:

const csrftoken = Cookies.get('csrftoken');

Примечание

Токен CSRF также присутствует в DOM в замаскированном виде, но только если он явно включен с помощью csrf_token в шаблоне. Cookie содержит каноничный, незамаскированный токен. CsrfViewMiddleware примет любой из них. Однако для защиты от атак BREACH рекомендуется использовать замаскированный токен.

Предупреждение

Если ваше представление не рендерит шаблон, содержащий тег шаблона csrf_token, Django может не установить cookie токена CSRF. Это часто происходит в случаях, когда формы динамически добавляются на страницу. Для решения этой проблемы Django предоставляет декоратор представления, который принудительно устанавливает cookie: ensure_csrf_cookie().

Получение токена, если CSRF_USE_SESSIONS или CSRF_COOKIE_HTTPONLY True

Если вы активируете CSRF_USE_SESSIONS или CSRF_COOKIE_HTTPONLY, вы должны включить токен CSRF в свой HTML и прочитать токен из DOM с помощью JavaScript:

{% csrf_token %}
<script>
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
</script>

Установка токена в запросе 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

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

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

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

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

Использование только декоратора не рекомендуется, так как если вы его забудете, у вас будет брешь в безопасности. Стратегия «с запасом» с использованием обоих методов приемлема и потребует минимальных затрат.

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

По умолчанию, если входящий запрос не проходит проверки, выполненные CsrfViewMiddleware, пользователю отправляется ответ «403 Forbidden». Это обычно происходит только при реальной атаке Cross-Site Request Forgery или когда из-за ошибки программирования токен 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, что привело бы к отправке необходимого куки 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.0/howto/csrf/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API