Защита от межсайтовых поддельных запросов
Средство промежуточного программного обеспечения CSRF и тег шаблона предоставляют простую в использовании защиту от межсайтовых поддельных запросов. Этот тип атаки происходит, когда вредоносный веб-сайт содержит ссылку, кнопку формы или какой-либо JavaScript, предназначенный для выполнения некоторого действия на вашем веб-сайте с использованием учетных данных вошедшего в систему пользователя, который посещает вредоносный сайт в своем браузере. Также рассматривается связанный тип атаки, «CSRF входа в систему», где атакующий сайт обманывает браузер пользователя, заставляя его войти в систему на сайте с чужими учетными данными.
Первая защита от атак CSRF заключается в обеспечении того, чтобы запросы GET (и другие «безопасные» методы, как определено в Разделе 9.2.1 RFC 9110) не имели побочных эффектов. Запросы через «опасные» методы, такие как POST, PUT и DELETE, могут затем защищаться путем выполнения шагов, изложенных в Использование защиты Django от CSRF.
Как это работает
Защита от CSRF основана на следующих вещах:
-
Куки CSRF, который представляет собой случайное секретное значение, к которому другие сайты не имеют доступа.
CsrfViewMiddlewareотправляет эти куки вместе с ответом всякий раз, когдаdjango.middleware.csrf.get_token()вызывается. Он также может отправлять их в других случаях. По соображениям безопасности значение секрета изменяется каждый раз при входе пользователя в систему. -
Скрытое поле формы с именем «csrfmiddlewaretoken», присутствующее во всех исходящих формах POST.
Чтобы защититься от атак BREACH, значение этого поля не просто секрет. Оно зашифровывается по-разному с каждым ответом с использованием маски. Маска генерируется случайным образом при каждом вызове
get_token(), поэтому значение поля формы различается каждый раз.Эта часть выполняется тегом шаблона
csrf_token. -
Для всех входящих запросов, не использующих HTTP GET, HEAD, OPTIONS или TRACE, должен быть присутствующим и правильным куки CSRF, а также поле «csrfmiddlewaretoken». Если это не так, пользователю будет возвращена ошибка 403.
При проверке значения поля «csrfmiddlewaretoken» сравнивается только секрет, а не полный токен, с секретом в значении куки. Это позволяет использовать постоянно меняющиеся токены. Хотя каждый запрос может использовать свой собственный токен, секрет остается общим для всех.
Эта проверка выполняется
CsrfViewMiddleware. -
CsrfViewMiddlewareпроверяет заголовок Origin, если он предоставлен браузером, по отношению к текущему хосту и настройкеCSRF_TRUSTED_ORIGINS. Это обеспечивает защиту от межподдоменных атак. -
Кроме того, для запросов HTTPS, если заголовок
Originне предоставлен,CsrfViewMiddlewareвыполняет строгую проверку referer. Это означает, что даже если поддомен может устанавливать или изменять куки на вашем домене, он не может заставить пользователя отправить POST-запрос на ваше приложение, поскольку этот запрос не будет исходить с вашего точного домена.Это также решает проблему атаки «человек посередине», возможной при использовании независимого от сеанса секрета под HTTPS, из-за того, что заголовки HTTP
Set-Cookie(к сожалению) принимаются клиентами даже в том случае, когда они взаимодействуют со сайтом под HTTPS. (Проверка referer не выполняется для запросов HTTP, поскольку наличие заголовкаRefererнедостаточно надёжно в HTTP.)Если настройка
CSRF_COOKIE_DOMAINустановлена, referer сравнивается с ней. Вы можете разрешить запросы с разных поддоменов, добавив префикс точкой. Например,CSRF_COOKIE_DOMAIN = '.example.com'позволит POST-запросам сwww.example.comиapi.example.com. Если настройка не установлена, то referer должен совпадать с заголовком HTTPHost.Расширение разрешенных referer за пределы текущего хоста или домена куки можно выполнить с помощью настройки
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 и отсутствие уязвимостей XSS на вашем сайте (потому что уязвимости XSS уже позволяют злоумышленнику сделать все, что позволяет уязвимость CSRF, и гораздо больше).
Удаление заголовка Referer
Чтобы избежать раскрытия URL referer сторонним сайтам, вы можете отключить referer на тегах <a> вашего сайта. Например, вы можете использовать тег <meta name="referrer" content="no-referrer"> или добавить заголовок Referrer-Policy: no-referrer. Из-за строгой проверки referer в защите CSRF для запросов HTTPS такие методы приведут к ошибке CSRF для запросов с «опасными» методами. Вместо этого используйте альтернативы, такие как <a rel="noreferrer" ...>", для ссылок на сторонние сайты.
Ограничения
Поддомены внутри сайта смогут устанавливать куки на клиенте для всего домена. Установив куки и используя соответствующий токен, поддомены смогут обойти защиту CSRF. Единственный способ избежать этого — убедиться, что поддомены контролируются доверенными пользователями (или, по крайней мере, не могут устанавливать куки). Обратите внимание, что даже без CSRF существуют другие уязвимости, такие как фиксация сеанса, которые делают предоставление поддоменов недоверенным сторонам плохой идеей, и эти уязвимости сложно исправить с помощью современных браузеров.
Утилиты
Примеры ниже предполагают использование представлений на основе функций. Если вы работаете с представлениями на основе классов, вы можете обратиться к Декорирование представлений на основе классов.
-
csrf_exempt(view)[source] -
Этот декоратор отмечает представление как освобождённое от защиты, обеспечиваемой средством промежуточного программного обеспечения. Пример:
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.
Настройки
Несколько настроек могут использоваться для управления поведением Django CSRF:
Часто задаваемые вопросы
Является ли проблемой, что защита CSRF Django по умолчанию не связана с сеансом?
Нет, это сделано по умолчанию. Отсутствие связи защиты 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/5.2/ref/csrf/