Защита от подделки межсайтовых запросов ¶
Промежуточное ПО CSRF и тег шаблона обеспечивают простую в использовании защиту от подделки межсайтовых запросов . Этот тип атаки происходит, когда вредоносный веб-сайт содержит ссылку, кнопку формы или некоторый код JavaScript, который предназначен для выполнения определенных действий на вашем веб-сайте с использованием учетных данных вошедшего в систему пользователя, который посещает вредоносный сайт в своем браузере. Также рассматривается родственный тип атаки, «CSRF входа в систему», когда атакующий сайт обманом заставляет браузер пользователя войти на сайт с чужими учетными данными.
Первая защита от атак CSRF - гарантировать, что запросы GET (и другие «безопасные» методы, как определено RFC 7231 # section-4.2.1 ) не имеют побочных эффектов. Запросы через «небезопасные» методы, такие как POST, PUT и DELETE, можно защитить, выполнив следующие действия.
Как пользоваться ¶
Чтобы воспользоваться преимуществами защиты CSRF в ваших представлениях, выполните следующие действия:
По умолчанию промежуточное ПО CSRF активировано в
MIDDLEWARE
настройках. Если вы переопределите этот параметр, помните, что он'django.middleware.csrf.CsrfViewMiddleware'
должен быть перед любым промежуточным программным обеспечением просмотра, которое предполагает, что CSRF-атаки были устранены.Если вы отключили его, что не рекомендуется, вы можете использовать его
csrf_protect()
в определенных представлениях, которые хотите защитить (см. Ниже).В любом шаблоне, который использует форму POST, используйте
csrf_token
тег внутри<form>
элемента, если форма предназначена для внутреннего URL-адреса, например:<form method="post">{% csrf_token %}
Этого не следует делать для форм POST, нацеленных на внешние URL-адреса, поскольку это приведет к утечке токена CSRF, что приведет к уязвимости.
В соответствующих функциях просмотра убедитесь, что
RequestContext
он используется для рендеринга ответа, чтобы он работал правильно. Если вы используете функцию, общие представления или приложения contrib, вы уже защищены, поскольку все они используют .{% csrf_token %}
render()
RequestContext
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
¶
Рекомендуемым источником для токена является csrftoken
файл cookie, который будет установлен, если вы включили защиту 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 CookiegetCookie
:
const csrftoken = Cookies.get('csrftoken');
Примечание
Маркер CSRF также присутствует в DOM, но только если он явно включен с использованием csrf_token
в шаблоне. Файл cookie содержит канонический токен; CsrfViewMiddleware
предпочтут печенье на маркер в DOM. В любом случае, вы гарантированно получите cookie, если токен присутствует в DOM, поэтому вы должны использовать cookie!
Предупреждение
Если ваше представление не отображает шаблон, содержащий csrf_token
тег шаблона, Django может не установить файл cookie токена CSRF. Это обычное дело в случаях, когда формы динамически добавляются на страницу. Для решения этого дела, Django предоставляет вид декоратор , который вынуждает установку куков:
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 */,
{headers: {'X-CSRFToken': csrftoken}}
);
fetch(request, {
method: 'POST',
mode: 'same-origin' // Do not send CSRF token to another domain.
}).then(function(response) {
// ...
});
Использование CSRF в шаблонах Jinja2 ¶
Бэкэнд Jinja2
шаблонов Django добавляет контекст всех шаблонов, что эквивалентно языку шаблонов Django. Например:{{ csrf_input }}
{% csrf_token %}
<form method="post">{{ csrf_input }}
Метод декоратора ¶
Вместо того, чтобы добавлять CsrfViewMiddleware
в качестве общей защиты, вы можете использовать csrf_protect
декоратор, который имеет точно такие же функциональные возможности, для определенных представлений, которые нуждаются в защите. Его необходимо использовать как в представлениях, которые вставляют токен CSRF в вывод, так и в тех, которые принимают данные формы POST. (Часто это одна и та же функция просмотра, но не всегда).
Использовать декоратор сам по себе не рекомендуется , поскольку, если вы забудете его использовать, у вас будет дыра в безопасности. Стратегия «пояс и подтяжки» с использованием обоих подходов хороша и потребует минимальных накладных расходов.
-
csrf_protect
( просмотр ) ¶ Декоратор, обеспечивающий защиту
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)
Если вы используете представления на основе классов, вы можете обратиться к разделу «Украшение представлений на основе классов» .
Отклоненные запросы ¶
По умолчанию пользователю отправляется ответ «403 Forbidden», если входящий запрос не прошел проверки, выполненные CsrfViewMiddleware
. Обычно это следует видеть только при наличии подлинной подделки межсайтового запроса или когда из-за ошибки программирования токен CSRF не был включен в форму POST.
Однако страница ошибок не очень удобна, поэтому вы можете предоставить собственное представление для обработки этого условия. Для этого установите
CSRF_FAILURE_VIEW
настройку.
Сбои CSRF регистрируются в журнале django.security.csrf как предупреждения .
Как это работает ¶
Защита CSRF основана на следующем:
Файл cookie CSRF, основанный на случайном секретном значении, к которому другие сайты не будут иметь доступа.
Этот файл cookie установлен
CsrfViewMiddleware
. Он отправляется с каждым вызванным ответомdjango.middleware.csrf.get_token()
(функция, используемая внутри для получения токена CSRF), если он еще не был установлен в запросе.Для защиты от атак BREACH токен - это не просто секрет; к секрету добавляется случайная маска, которая используется для его шифрования.
По соображениям безопасности значение секрета изменяется каждый раз, когда пользователь входит в систему.
Скрытое поле формы с именем csrfmiddlewaretoken, присутствующее во всех исходящих формах POST. Значение этого поля, опять же, является значением секрета с маской, которая добавляется к нему и используется для его шифрования. Маска восстанавливается при каждом вызове,
get_token()
так что значение поля формы изменяется в каждом таком ответе.Эта часть выполняется тегом шаблона.
Для всех входящих запросов, которые не используют HTTP GET, HEAD, OPTIONS или TRACE, должен присутствовать файл cookie CSRF, а поле csrfmiddlewaretoken должно присутствовать и быть правильным. В противном случае пользователь получит ошибку 403.
При проверке значения поля csrfmiddlewaretoken только секрет, а не полный токен, сравнивается с секретом в значении файла cookie. Это позволяет использовать постоянно меняющиеся токены. Хотя каждый запрос может использовать свой собственный токен, секрет остается общим для всех.
Эта проверка выполняется
CsrfViewMiddleware
.Кроме того, для запросов HTTPS строгая проверка ссылки выполняется с помощью
CsrfViewMiddleware
. Это означает, что даже если поддомен может устанавливать или изменять файлы cookie в вашем домене, он не может заставить пользователя публиковать сообщения в вашем приложении, поскольку этот запрос не будет поступать из вашего собственного домена.Это также относится к атаке «человек посередине», которая возможна при использовании HTTPS при использовании секрета, не зависящего от сеанса, из-за того, что HTTP-
Set-Cookie
заголовки (к сожалению) принимаются клиентами, даже когда они общаются с сайтом по HTTPS. (Проверка ссылок не выполняется для HTTP-запросов, потому что наличиеReferer
заголовка недостаточно надежно для HTTP.)Если
CSRF_COOKIE_DOMAIN
параметр установлен, референт сравнивается с ним. Вы можете разрешить запросы между субдоменами, добавив точку в начале. Например, разрешит запросы POST от и . Если параметр не установлен, то ссылка должна соответствовать заголовку HTTP .CSRF_COOKIE_DOMAIN = '.example.com'
www.example.com
api.example.com
Host
Расширение допустимых рефереров за пределы текущего хоста или домена cookie можно выполнить с помощью этой
CSRF_TRUSTED_ORIGINS
настройки.
Это гарантирует, что только формы, созданные из доверенных доменов, могут быть использованы для возврата данных POST.
Он намеренно игнорирует запросы GET (и другие запросы, которые определены как «безопасные» RFC 7231 # раздел-4.2.1 ). Эти запросы никогда не должны иметь потенциально опасных побочных эффектов, поэтому CSRF-атака с запросом GET должна быть безвредной.RFC 7231 # section-4.2.1 определяет POST, PUT и DELETE как «небезопасные», и все другие методы также считаются небезопасными для максимальной защиты.
Защита CSRF не может защитить от атак типа «злоумышленник в середине», поэтому используйте HTTPS с HTTP Strict Transport Security . Он также предполагает проверку заголовка HOST и отсутствие на вашем сайте каких - либо уязвимостей межсайтового скриптинга (поскольку уязвимости XSS уже позволяют злоумышленнику делать все, что позволяет уязвимость CSRF, и намного хуже).
Удаление Referer
заголовка
Чтобы избежать раскрытия URL-адреса реферера сторонним сайтам, вы можете отключить реферер в <a>
тегах вашего сайта . Например, вы можете использовать тег или включить заголовок. Из-за строгой проверки реферера защиты CSRF для запросов HTTPS эти методы вызывают сбой CSRF для запросов с «небезопасными» методами. Вместо этого используйте альтернативы, такие как ссылки на сторонние сайты.<meta name="referrer" content="no-referrer">
Referrer-Policy: no-referrer
<a rel="noreferrer" ...>"
Кеширование ¶
Если 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):
...
Если вы используете представления на основе классов, вы можете обратиться к разделу «Украшение представлений на основе классов» .
Тестирование ¶
CsrfViewMiddleware
Обычно будет большой помехой для тестирования функции представления , в связи с необходимостью для CSRF токена , который должен быть отправлен с каждым запросом POST. По этой причине HTTP-клиент Django для тестов был изменен, чтобы установить флаг для запросов, который ослабляет промежуточное программное обеспечение и csrf_protect
декоратор, чтобы они больше не отклоняли запросы. Во всем остальном (например, отправка файлов cookie и т. Д.) Они ведут себя одинаково.
Если по какой-то причине вы хотите, чтобы тестовый клиент выполнял проверки CSRF, вы можете создать экземпляр тестового клиента, который выполняет проверки CSRF:
>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)
Ограничения ¶
Субдомены на сайте смогут устанавливать файлы cookie на клиенте для всего домена. Установив файл cookie и используя соответствующий токен, поддомены смогут обойти защиту CSRF. Единственный способ избежать этого - убедиться, что поддомены контролируются доверенными пользователями (или, по крайней мере, не могут устанавливать файлы cookie). Обратите внимание, что даже без CSRF существуют другие уязвимости, такие как фиксация сеанса, из-за которых предоставление субдоменов ненадежным сторонам является плохой идеей, и эти уязвимости нелегко исправить с помощью текущих браузеров.
Пограничные случаи ¶
Некоторые представления могут иметь необычные требования, что означает, что они не соответствуют нормальному шаблону, предусмотренному здесь. В этих ситуациях может быть полезен ряд утилит. Сценарии, в которых они могут понадобиться, описаны в следующем разделе.
Утилиты ¶
В приведенных ниже примерах предполагается, что вы используете представления на основе функций. Если вы работаете с представлениями на основе классов, вы можете обратиться к разделу «Украшение представлений на основе классов» .
-
csrf_exempt
( просмотр ) ¶ Этот декоратор отмечает, что представление освобождается от защиты, обеспечиваемой промежуточным программным обеспечением. Пример:
from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt @csrf_exempt def my_view(request): return HttpResponse('Hello world')
-
requires_csrf_token
( просмотр ) ¶ Обычно
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)
Этот декоратор заставляет представление отправлять файл cookie CSRF.
Сценарии ¶
Защита 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
должен быть самым внутренним декоратором).
View нуждается в защите для одного пути ¶
Представлению нужна защита 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
которая могла бы вызвать отправку необходимого файла cookie CSRF.
Решение: используйте ensure_csrf_cookie()
в представлении, которое отправляет страницу.
Contrib и многоразовые приложения ¶
Поскольку разработчик может отключить CsrfViewMiddleware
, все соответствующие представления в приложениях contrib используют csrf_protect
декоратор для обеспечения защиты этих приложений от CSRF. Рекомендуется, чтобы разработчики других многоразовых приложений, которым нужны такие же гарантии, также использовали
csrf_protect
декоратор для своих представлений.
Настройки ¶
Для управления поведением CSRF Django можно использовать ряд настроек:
Часто задаваемые вопросы ¶
Является ли публикация произвольной пары токенов CSRF (данные cookie и POST) уязвимостью? ¶
Нет, это сделано намеренно. Без атаки типа «человек посередине» злоумышленник не сможет отправить файл cookie с токеном CSRF в браузер жертвы, поэтому для успешной атаки потребуется получить файл cookie браузера жертвы с помощью XSS или аналогичного средства, и в этом случае злоумышленнику обычно не нужны CSRF-атаки.
Некоторые инструменты аудита безопасности отмечают это как проблему, но, как упоминалось ранее, злоумышленник не может украсть файл cookie CSRF браузера пользователя. «Кража» или изменение вашего собственного токена с помощью Firebug, инструментов разработчика Chrome и т. Д. Не является уязвимостью.
Проблема в том, что защита Django от CSRF по умолчанию не связана с сеансом? ¶
Нет, это сделано намеренно. Отсутствие привязки защиты CSRF к сеансу позволяет использовать защиту на таких сайтах, как pastebin, которые позволяют отправлять сообщения от анонимных пользователей, у которых нет сеанса.
Если вы хотите сохранить токен CSRF в сеансе пользователя, используйте
CSRF_USE_SESSIONS
параметр.
Почему пользователь может столкнуться с ошибкой проверки CSRF после входа в систему? ¶
По соображениям безопасности токены CSRF меняются каждый раз, когда пользователь входит в систему. Любая страница с формой, созданной до входа в систему, будет иметь старый, недопустимый токен CSRF, и ее необходимо будет перезагрузить. Это может произойти, если пользователь нажмет кнопку «Назад» после входа в систему или войдет в другую вкладку браузера.