• 3.1
  • 3.2
  • 6.1
  • Версия документации: 5.0

Подделка межсайтового запроса (CSRF)

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

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

Как это работает

CSRF базируется на следующих вещах:

  1. Файл cookie CSRF, представляющий собой случайное секретное значение, к которому другие сайты не будут иметь доступа.

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

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

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

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

  3. Все HTTP запросы, которые не GET, HEAD, OPTIONS или TRACE, должны содержать CSRF куку, и поле „csrfmiddlewaretoken“ с правильным значением. Иначе пользователь получит 403 ошибку.

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

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

  4. CsrfViewMiddleware проверяет ``Заголовок Origin`_, если он предоставлен браузером, на соответствие текущему хосту и настройке CSRF_TRUSTED_ORIGINS. Это обеспечивает защиту от междоменных атак.

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

    В дополнение для HTTPS запросов в CsrfViewMiddleware проверяется «referer»(источник запроса). Это необходимо для предотвращения MITM-атаки(Man-In-The-Middle), которая возможна при использовании HTTPS и токена не привязанного к сессии, т.к. клиенты принимают(к сожалению) HTTP заголовок „Set-Cookie“, несмотря на то, что коммуникация с сервером происходит через HTTPS. (Такая проверка не выполняется для HTTP запросов т.к. «Referer» заголовок легко подменить при использовании HTTP.)

    Если установлен параметр CSRF_COOKIE_DOMAIN, референт сравнивается с ним. Вы можете разрешить запросы между поддоменами, включив точку в начале. Например, CSRF_COOKIE_DOMAIN = .example.com разрешит запросы POST от www.example.com и api.example.com. Если параметр не установлен, то реферер должен соответствовать заголовку HTTP Host.

    Чтобы расширить список доступных доменов, кроме текущего хоста и домена кук, используйте CSRF_TRUSTED_ORIGINS.

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

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

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

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

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

Ограничения

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

Утилиты

Примеры ниже предполагают, чтобы используете представления-функции. Если вы используете представления-классы, обратитесь к этому разделу.

csrf_exempt(view)

Этот декоратор позволяет исключить представление из процесса проверки CSRF. Например:

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


@csrf_exempt
def my_view(request):
    return HttpResponse("Hello world")
Changed in Django 5.0:

Добавлена ​​поддержка переноса функций асинхронного представления.

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)
Changed in Django 5.0:

Добавлена ​​поддержка переноса функций асинхронного представления.

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)
Changed in Django 5.0:

Добавлена ​​поддержка переноса функций асинхронного представления.

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

Changed in Django 5.0:

Добавлена ​​поддержка переноса функций асинхронного представления.

Настройки

Параметры, которые могут быть использованы для управления поведением CSRF в Django:

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

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

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

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

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

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

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

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

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

Back to Top