Spec-Zone.ru › Django 4.1

Как использовать защиту 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 для ваших представлений, как описано выше.

CSRF-cookie токена по умолчанию имеет имя 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 может не установить CSRF-cookie. Это распространено в случаях, когда формы динамически добавляются на страницу. Для решения этой проблемы 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

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

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

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

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

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

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

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

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

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

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

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

Однако, если вы используете декораторы кэширования для отдельных представлений, средство промежуточного ПО CSRF ещё не смогло установить заголовок Vary или CSRF-cookie, и ответ будет кэширован без них. В этом случае для всех представлений, которые потребуют вставки 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/4.1/howto/csrf/

Spec-Zone.ru

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