Spec-Zone.ru › Django 6.0

Защита от межсайтовой подделки запросов

Промежуточное ПО CSRF и тег шаблона обеспечивают простую в использовании защиту от межсайтовой подделки запросов. Этот тип атаки происходит, когда вредоносный веб-сайт содержит ссылку, кнопку формы или JavaScript-код, предназначенные для выполнения каких-либо действий на вашем веб-сайте с использованием учётных данных вошедшего в систему пользователя, посетившего вредоносный сайт в браузере. Также рассматривается связанный тип атаки — «CSRF при входе в систему», при котором атакующий сайт обманом заставляет браузер пользователя войти на сайт с учётными данными другого человека.

Первая мера защиты от CSRF-атак — убедиться, что GET-запросы (и другие «безопасные» методы, как определено в разделе 9.2.1 RFC 9110) не вызывают побочных эффектов. Затем запросы с использованием «небезопасных» методов, таких как POST, PUT и DELETE, можно защитить с помощью действий, описанных в разделе Как использовать защиту Django от CSRF.

Как работает защита от CSRF

Защита от CSRF основана на следующем:

  1. CSRF-cookie — это случайное секретное значение, к которому другие сайты не имеют доступа.

    CsrfViewMiddleware отправляет эту cookie в ответе при каждом вызове django.middleware.csrf.get_token(). Она может отправляться и в других случаях. В целях безопасности значение секрета меняется каждый раз, когда пользователь входит в систему.

  2. Скрытое поле формы с именем ‘csrfmiddlewaretoken’, присутствующее во всех исходящих POST-формах.

    Для защиты от атак BREACH значение этого поля не является самим секретом. При каждом ответе оно по-разному перемешивается с помощью маски. Маска генерируется случайным образом при каждом вызове get_token(), поэтому значение поля формы каждый раз отличается.

    Эту часть обеспечивает тег шаблона csrf_token.

  3. Для всех входящих запросов, использующих HTTP-метод, отличный от GET, HEAD, OPTIONS или TRACE, должна присутствовать CSRF-cookie, а поле ‘csrfmiddlewaretoken’ должно присутствовать и содержать правильное значение. В противном случае пользователь получит ошибку 403.

    При проверке значения поля ‘csrfmiddlewaretoken’ с секретом в значении cookie сравнивается только секрет, а не весь токен. Это позволяет использовать постоянно меняющиеся токены. Хотя для каждого запроса может использоваться свой токен, секрет остаётся общим для всех.

    Эту проверку выполняет CsrfViewMiddleware.

  4. CsrfViewMiddleware проверяет заголовок Origin, если браузер его передал, сверяя его с текущим хостом и настройкой CSRF_TRUSTED_ORIGINS. Это обеспечивает защиту от атак с межсайтовых поддоменов.
  5. Кроме того, для HTTPS-запросов, если заголовок Origin не передан, CsrfViewMiddleware выполняет строгую проверку referer. Это означает, что даже если поддомен может устанавливать или изменять cookie для вашего домена, он не сможет заставить пользователя отправить запрос в ваше приложение, поскольку запрос будет поступать не с вашего точного домена.

    Это также устраняет атаку «человек посередине», возможную при использовании HTTPS с секретом, не связанным с сеансом, поскольку HTTP-заголовки Set-Cookie (к сожалению) принимаются клиентами, даже когда они обращаются к сайту по HTTPS. (Для HTTP-запросов проверка referer не выполняется, поскольку наличие заголовка Referer при использовании HTTP недостаточно надёжно.)

    Если задана настройка CSRF_COOKIE_DOMAIN, referer сравнивается с её значением. Разрешить запросы с поддоменов можно, добавив точку в начале. Например, CSRF_COOKIE_DOMAIN = '.example.com' разрешит POST-запросы с www.example.com и api.example.com. Если настройка не задана, referer должен совпадать с HTTP-заголовком Host.

    Расширить список допустимых referer за пределы текущего хоста или домена cookie можно с помощью настройки CSRF_TRUSTED_ORIGINS.

Это гарантирует, что для отправки данных методом POST можно использовать только формы, созданные на доверенных доменах.

Проверка намеренно игнорирует GET-запросы (и другие запросы, определённые как «безопасные» в разделе 9.2.1 RFC 9110). Такие запросы никогда не должны вызывать потенциально опасных побочных эффектов, поэтому CSRF-атака с помощью GET-запроса должна быть безвредной. В разделе 9.2.1 RFC 9110 методы POST, PUT и DELETE определены как «небезопасные»; для максимальной защиты все остальные методы также считаются небезопасными.

Защита от CSRF не защищает от атак «человек посередине», поэтому используйте HTTPS вместе с HTTP Strict Transport Security. Также предполагается, что выполняется проверка заголовка HOST и на вашем сайте нет уязвимостей межсайтового скриптинга (поскольку такие уязвимости и без того позволяют атакующему делать всё, что возможно при уязвимости CSRF, и даже больше).

Удаление заголовка Referer

Чтобы не раскрывать URL-адрес источника сторонним сайтам, можно отключить referer для тегов <a> на своём сайте. Например, можно использовать тег <meta name="referrer" content="no-referrer"> или включить заголовок Referrer-Policy: no-referrer. Из-за строгой проверки referer при HTTPS-запросах в рамках защиты от CSRF эти способы приведут к ошибке CSRF для запросов с «небезопасными» методами. Вместо этого используйте альтернативы, например <a rel="noreferrer" ...>", для ссылок на сторонние сайты.

Ограничения

Поддомены сайта могут устанавливать на клиенте cookie для всего домена. Установив cookie и используя соответствующий токен, поддомены смогут обойти защиту от CSRF. Единственный способ избежать этого — убедиться, что поддомены контролируются доверенными пользователями (или, по крайней мере, не могут устанавливать cookie). Обратите внимание: даже без CSRF существуют другие уязвимости, например фиксация сессии, поэтому предоставлять поддомены недоверенным лицам — плохая идея. Эти уязвимости нелегко устранить средствами современных браузеров.

Вспомогательные средства

В приведённых ниже примерах предполагается, что вы используете представления на основе функций. Если вы работаете с представлениями на основе классов, обратитесь к разделу Декорирование представлений на основе классов.

csrf_exempt(view) [исходный код]

Этот декоратор помечает представление как исключённое из защиты, обеспечиваемой промежуточным ПО. Пример:

from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt


@csrf_exempt
def my_view(request):
    return HttpResponse("Hello world")
csrf_protect(view)

Декоратор, обеспечивающий представлению защиту, которую предоставляет CsrfViewMiddleware.

Использование:

from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect


@csrf_protect
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)
requires_csrf_token(view)

Обычно тег шаблона csrf_token не работает, если не был вызван CsrfViewMiddleware.process_view или аналогичный механизм, например csrf_protect. Декоратор представления requires_csrf_token можно использовать, чтобы обеспечить работу тега шаблона. Этот декоратор работает аналогично csrf_protect, но никогда не отклоняет входящий запрос.

Пример:

from django.shortcuts import render
from django.views.decorators.csrf import requires_csrf_token


@requires_csrf_token
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)
ensure_csrf_cookie(view)

Этот декоратор заставляет представление отправлять CSRF-cookie.

Настройки

Для управления поведением Django в отношении CSRF можно использовать несколько настроек:

  • CSRF_COOKIE_AGE
  • CSRF_COOKIE_DOMAIN
  • CSRF_COOKIE_HTTPONLY
  • CSRF_COOKIE_NAME
  • CSRF_COOKIE_PATH
  • CSRF_COOKIE_SAMESITE
  • CSRF_COOKIE_SECURE
  • CSRF_FAILURE_VIEW
  • CSRF_HEADER_NAME
  • CSRF_TRUSTED_ORIGINS
  • CSRF_USE_SESSIONS

Часто задаваемые вопросы

Является ли уязвимостью отправка произвольной пары CSRF-токенов (cookie и данные POST)?

Нет, так задумано. Без атаки «человек посередине» атакующий не может отправить CSRF-токен в cookie браузера жертвы. Поэтому для успешной атаки потребуется получить cookie браузера жертвы через XSS или аналогичный способ; в таком случае атакующему обычно не нужны CSRF-атаки.

Некоторые инструменты аудита безопасности указывают на это как на проблему, но, как упоминалось выше, атакующий не может украсть CSRF-cookie из браузера пользователя. «Кража» или изменение собственного токена с помощью Firebug, инструментов разработчика Chrome и т. д. не является уязвимостью.

Проблема ли то, что защита Django от CSRF по умолчанию не связана с сеансом?

Нет, так задумано. Отсутствие привязки защиты от CSRF к сеансу позволяет использовать её на таких сайтах, как pastebin, которые принимают сообщения от анонимных пользователей без сеанса.

Если вы хотите хранить CSRF-токен в сеансе пользователя, используйте настройку CSRF_USE_SESSIONS.

Почему после входа в систему пользователь может столкнуться с ошибкой проверки CSRF?

В целях безопасности CSRF-токены меняются каждый раз, когда пользователь входит в систему. На любой странице с формой, созданной до входа в систему, будет старый недействительный CSRF-токен, поэтому такую страницу нужно перезагрузить. Это может произойти, если пользователь нажмёт кнопку «Назад» после входа или войдёт в систему в другой вкладке браузера.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/ref/csrf/

Spec-Zone.ru

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