Django CSRF Руководство
Иногда проще создать сайт, не думая о безопасности. И часто, возможно, из-за сжатых сроков, вы можете забыть о необходимости учитывать основные меры безопасности.
Для пользы ваших приложений и ваших пользователей имеет смысл узнать об атаках безопасности в целом — и понять необходимость и использование мер безопасности для всех ваших веб-приложений в частности.
Cуществует множество популярных атак на безопасность. Межсайтовая подделка запроса (CSRF) — одна из них.
В Django есть несколько способов предотвратить атаки CSRF. А разработчикам Django стоит обратить внимание на меры против CSRF-атак.
В этом посте мы поговорим о том, что такое CSRF и как он работает.
Что такое CSRF?
CSRF (или XSRF) также известен как подделка межсайтовых запросов. Как следует из названия, CSRF — это своего рода атака на сайты, в основном выполняемая другими (вредоносными) сайтами, а иногда и (злонамеренным) пользователем на сайте.
Как правило, во многих случаях сайт требует от пользователя ввода данных с другого веб-сайта от имени этого конкретного пользователя. Примером может служить то, как многие блоги используют Disqus для поддержки своих систем комментирования. Чтобы оставлять комментарии в этом конкретном блоге, вам необходимо сначала войти в систему Disqus. Это базовое использование CDN, и этот пример представляет собой законный межсайтовый запрос.
CSRF-атаки обычно полагаются на личность пользователя. Так что же происходит, когда пользователь посещает вредоносный сайт? Этот сайт отправляет скрытые формы некоторого JavaScript XMLHttpRequest. Этот запрос использует учетные данные пользователя (того, кто посетил их вредоносный сайт) для выполнения некоторых действий на другом сайте, который доверяет браузеру или личности пользователя.
Сайт обычно идентифицирует аутентифицированных пользователей, сохраняя файлы cookie с заголовками и контентом, которые представляют этого конкретного пользователя в их браузерах. Злоумышленники используют это, чтобы получить доступ к учетным данным пользователя для выполнения своих атак.
Пример: Фрэнк и банк
Некий неизвестный злоумышленник хочет получить доступ к банковскому счету Фрэнка и украсть его деньги. Что произойдет, если банк Фрэнка уязвим для CSRF?
Для перевода наличных Фрэнк должен использовать определенный URL-адрес, сохраненный в его браузере, например http://example_a_bank.com/app/service/transfer?amount=20000&destination=example_b_bank&accountNumber=9567265100.
Передача прошла успешно. Затем браузер сохраняет сеанс cookie с учетными данными Фрэнка, и Фрэнк продолжает.
У неизвестного злоумышленника есть вредоносный сайт, на который, вероятно, невинно перешел Фрэнк. В результате злоумышленник разместил на вредоносном сайте HTML-код, который выглядит следующим образом:
Теперь, когда Фрэнк посещает вредоносный веб-сайт, браузер будет думать, что загружает или обрабатывает ссылку на изображение. Он отправит запрос GET для получения изображения, но он также отправит запрос в банк Фрэнка на перевод 60 000 долларов на указанный злоумышленником банковский счет. В фактическом банке все еще есть сеанс cookie, сохраненный в браузере Фрэнка. Поэтому системы банка считают это реальным запросом и обрабатывают его.
Это очень серьезная уязвимость! Как банки и другие предприятия могут этого избежать? Давайте рассмотрим, как включить защиту CSRF в Django.
CSRF в Django
Middleware в Django — это набор функций, которые выполняются во время процессов запроса и ответа. А в Django есть CSRF middleware, которое помогает защитить от атак CSRF в Django приложениях .
Когда вы запускаете проект Django, в файле settings.py вы увидите, что middleware активировано по умолчанию.
'django.middleware.csrf.CsrfViewMiddleware'
Как использовать CSRF middleware
Step 1
Вам нужно добавить django.middleware.csrf.CsrfViewMiddleware в файл settings.py, чтобы включить его.
По умолчанию в Django это уже включено, как в следующем примере:
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', #Csrf Middleware is added 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
Step 2
Django имеет тег шаблона, который упрощает использование защиты CSRF:
В шаблоне, который использует форму POST, используйте csrf_token внутри элемента .
Метод CSRF декоратора
Вы хотите использовать защиту CSRF для конкретной виушки? Тогда декоратор csrf_protect вам подойдет. Он имеет те же функции, что и CsrfViewMiddleware, но работает только с теми виушками, которым вы его назначили.
from django.shortcuts import render from django.views.decorators.csrf import csrf_protect @csrf_protect def user(request): user = <> # . return render(request, "user_view.html", user)
ПРИМЕЧАНИЕ! Лучше использовать CsrfViewMiddleware в качестве общей защиты. Если вы забудете добавить декоратор к своим виушкам, это создаст проблемы с безопасностью. Вы должны использовать его в виушкаx, которые назначают токены CSRF для вывода, и в виушкаx, которые принимают данные из формы POST.
Вы также можете использовать CsrfViewMiddleware в качестве общей защиты и по-прежнему решать, какая виушка будет использовать его. Например:
from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt @csrf_exempt def user(request): return HttpResponse('CSRF token is being exempted here!')
Декоратор csrf_exempt отмечает виушкy и освобождает ее от защиты, которую middleware обеспечивает для всех виушкаx.
Другие методы декоратора
Вот еще несколько способов, которые могут вам пригодиться.
csrf_exempt (view): помечает виушкy как освобожденное от защиты CSRF.
requires_csrf_token (view): это гарантирует, что тег шаблона csrf_token работает. Его функция похожа на crsf_protect, но он не отклоняет входящий запрос.
sure_csrf_cookie (views): заставляет виушкy установить CSRF cookie, даже если тег шаблона csrf_token не используется.
Как работает токен CSRF?
Токен CSRF похож на буквенно-цифровой код или случайное секретное значение, характерное для этого конкретного сайта. Следовательно, ни один другой сайт не имеет такого же кода.
Скрытое поле формы с полем csrfmiddlewaretoken присутствует во всех исходящих запросах. Когда вы отправляете на сервер форму, которую он не отправлял вам, сервер не примет ее, пока у него нет CSRF токена, совпадающего с тем, который распознает сервер.
У сервера есть собственный CSRF токен. Это то, что он отправляет клиенту вместе с формой для защиты информации.
Все входящие запросы должны иметь CSRF cookie, а поле csrfmiddlewaretoken должно присутствовать и быть правильным. В противном случае пользователь получит ошибку 403.
Включение защиты CSRF с помощью Django, REST и React
А как насчет случаев, когда вы используете Django REST и отдельный фреймворк, такой как React? Вы обязательно захотите убедиться, что у вас также включена защита CSRF.
Использование React Forms для рендеринга токена CSRF
Django позволяют легко включать:
внутри форм. Однако в React вам придется пройти более длинный путь, чтобы отрендерить его самостоятельно.
Шаг 1
Вам нужно получить токен csrf из файла cookie csrf_token. Но это будет установлено, только если в Django включено CSRF middleware.
В официальной документации Django можно получить токен в JavaScript следующим образом:
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');
Шаг 2
Затем вы можете создать глобальный файл csrftoken.js со следующим:
import React from 'react'; const csrftoken = getCookie('csrftoken'); const CSRFTOKEN = () => < return ( type="hidden" /> ); >; export default CSRFTOKEN;
Теперь его проще импортировать и включать в как можно больше форм:
import CSRFTOKEN from './csrftoken'; class SampleForm extends Component < render() < return (); > > export default SampleForm;
Отправка запроса FETCH с Django CSRF токеном в React
Кроме того, теперь вы также можете легко отправить FETCH запрос при назначении заголовка X-CSRFToken:
fetch(url, < credentials: 'include', method: 'POST', mode: 'same-origin', headers: < 'Accept': 'application/json', 'Content-Type': 'application/json', 'X-CSRFToken': csrftoken >, body: <> >) >
Вы смогли включить Django csrf_token в React. Ура!
Вывод
Теперь вы узнали, что такое защита CSRF и как включить ее в Django. Это означает, что вы на шаг впереди атак на безопасность и злонамеренных попыток против ваших пользователей.
Этот пост был написан не так, как я обычно пишу. Будущие посты будут в обычном стиле, но я надеюсь, что вам понравился и этот!
CSRF
CSRF (cross-site request forgery, подделка межсайтовых запросов) — вид атак на сайт, при которой злоумышленник с помощью мошеннического сайта или скрипта заставляет браузер пользователя выполнять на доверенном сайте действия от его имени: отправлять сообщения, менять пароли, переводить деньги со счета на счет и пр. В атаке используются недостатки протокола HTTP.
Освойте профессию «Белый хакер»
Чтобы стать жертвой, пользователю достаточно перейти по ссылке от мошенника, которая может быть изменена с помощью сокращателя. Например, человек, авторизованный на сайте банка, может кликнуть по фишинговой ссылке с запросом на перевод денег на счет мошенника. Из-за авторизации обработается запрос на перевод.
CSRF-атака не подходит для кражи конфиденциальных данных, так как итоговый запрос, выполняющий основное действие, не отправляет их мошеннику.
Профессия / 13 месяцев
«Белый» хакер
Взламывайте ПО безнаказанно и за оплату
Как работает межсайтовая подделка запросов
Разобраться, как работает межсайтовая подделка запросов, поможет понятие сессионных cookies (куки).
Сессионные cookies — это небольшой набор данных, которые веб-сервер отправляет браузеру при посещении сайта. Они хранятся на компьютерах пользователей и используются для их идентификации. Именно благодаря cookies не нужно авторизовываться на сайте дважды, а в корзине интернет-магазина содержится все, что было добавлено, даже если страницу перезагрузили.
После сохранения браузер отправляет cookies на сервер с каждым запросом и идентифицирует пользователя. С их помощью злоумышленник может выдать себя за потенциальную жертву и заставить ее браузер выполнить запрос. Если пользователь уже авторизован на сайте, cookies отправятся автоматически вместе с запросом.
Для выполнения CSRF необходимы несколько условий:
- на уязвимом сайте есть действие, которое хакер хочет выполнить от имени жертвы, например изменить адрес @mail, осуществить перевод денежных средств, изменить пароль и так далее;
- злоумышленник заранее знает все параметры запроса, которые ожидает увидеть уязвимый сайт. Даже незначительное отличие в тексте повлияет на работоспособность;
- действие полагается только на файлы cookies для верификации пользователя и выполняется с помощью HTTP-запросов.
CSRF-атаке могут быть подвержены все сайты и веб-приложения, которые добавляют данные для аутентификации пользователя к HTTP-запросу автоматически.
Либо злоумышленник может обманом заставить жертву загрузить или отправить информацию. Например, через фишинговую ссылку.
Она может быть скрыта в теге изображения:
Или замаскирована под обычную ссылку:
Станьте специалистом
по кибербезопасности – научитесь отражать кибератаки и поддерживать безопасность любых IT-систем
Как защитить сайт от CSRF-атак
Некоторые фреймворки имеют встроенную защиту от CSRF-атак. Например .NET или Laravel. Если ее нет, можно использовать следующие способы.
SOP
SOP (same-origin policy, политика одинакового источника) определяет то, как именно скрипт или документ, который загружен из оригинального источника (origin), будет взаимодействовать с ресурсом, загруженным из другого источника. Две страницы имеют одинаковый источник, если у них совпадают хост (host), порт (port) и протокол (http или https). Часто можно встретить также запись вида scheme/host/port tuple. Это позволяет изолировать документы, которые могут нанести вред, и снизить количество вероятных векторов атак.
Токены CSRF
CSRF-токены (или anti-CSRF-токены) напоминают cookies. Это такие же данные, которые сервер отправляет браузеру в ожидании получить их обратно, но отличие в следующем: сервер должен отправить браузеру уникальный токен и проверить, присылает ли его браузер в ответ в запросе. Если токены совпадают, запрос действителен, если нет — отклоняется.
Токен должен удовлетворять требованиям:
- иметь конечное время жизни;
- генерироваться с использованием криптографии генератором псевдослучайных чисел;
- иметь такую длину, чтобы быть устойчивым к перебору;
- использоваться только один раз.
Также можно использовать два токена. Кроме токена, сохраненного в параметрах ответа, существует второй, размещенный в сессионных cookies. Таким образом сервер, получая запрос, проверяет два токена вместо одного. Такую защиту намного сложнее преодолеть.
Флаг Same-Site Cookies
Метод похож на использование SOP. Отличие в том, что флаг Same-Site помечает куки для одного доменного имени. В результате источник запроса подвергается проверке. Считается, что cookies и источник запроса имеют одинаковое происхождение, если протокол, порт (если применимо) и хост (но не IP-адрес) одинаковы для обоих. Таким образом не получится отправить запрос с мошеннического сайта. Флаг поддерживает подавляющее большинство современных браузеров, и его использование является хорошей практикой в стратегии защиты.
Подтверждение действий от пользователя
Для отправки денежных средств, изменения аутентификационных данных и т.д. хорошая практика — дополнительное подтверждающее действие. Например, после попытки смены пароля можно попросить пользователя нажать на кнопку на сайте или ввести капчу. Это является еще одной отправкой запроса. Вместе с вышеупомянутыми методами это обеспечивает надежную защиту сайта и веб-приложения.
«Белый» хакер
Научитесь защищать информационные системы: проводить атаки, анализировать программы и искать в них уязвимости. Станьте востребованным специалистом и работайте из любой точки мира.
Защита от подделки межсайтовых запросов ¶
Промежуточное ПО 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 тег внутри элемента, если форма предназначена для внутреннего URL-адреса, например:
form method="post"> csrf_token %>
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 Cookie getCookie :
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. Например: >
form method="post"> <csrf_input >>
Метод декоратора ¶
Вместо того, чтобы добавлять CsrfViewMiddleware в качестве общей защиты, вы можете использовать csrf_protect декоратор, который имеет точно такие же функциональные возможности, для определенных представлений, которые нуждаются в защите. Его необходимо использовать как в представлениях, которые вставляют токен CSRF в вывод, так и в тех, которые принимают данные формы POST. (Часто это одна и та же функция просмотра, но не всегда).
Использовать декоратор сам по себе не рекомендуется , поскольку, если вы забудете его использовать, у вас будет дыра в безопасности. Стратегия «пояс и подтяжки» с использованием обоих подходов хороша и потребует минимальных накладных расходов.
Декоратор, обеспечивающий защиту 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 заголовка
Кеширование ¶
Если 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 существуют другие уязвимости, такие как фиксация сеанса, из-за которых предоставление субдоменов ненадежным сторонам является плохой идеей, и эти уязвимости нелегко исправить с помощью текущих браузеров.
Пограничные случаи ¶
Некоторые представления могут иметь необычные требования, что означает, что они не соответствуют нормальному шаблону, предусмотренному здесь. В этих ситуациях может быть полезен ряд утилит. Сценарии, в которых они могут понадобиться, описаны в следующем разделе.
Утилиты ¶
В приведенных ниже примерах предполагается, что вы используете представления на основе функций. Если вы работаете с представлениями на основе классов, вы можете обратиться к разделу «Украшение представлений на основе классов» .
Этот декоратор отмечает, что представление освобождается от защиты, обеспечиваемой промежуточным программным обеспечением. Пример:
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)
ensure_csrf_cookie ( просмотр ) ¶
Этот декоратор заставляет представление отправлять файл cookie CSRF.
Сценарии ¶
Защита CSRF должна быть отключена только для нескольких просмотров ¶
Большинство представлений требует защиты CSRF, но некоторые нет.
Решение: вместо того, чтобы отключать промежуточное программное обеспечение и применять его csrf_protect ко всем представлениям, которые в нем нуждаются, включите промежуточное программное обеспечение и используйте csrf_exempt() .
CsrfViewMiddleware.process_view не используется ¶
Бывают случаи, когда CsrfViewMiddleware.process_view может не выполняться до запуска вашего представления — например, обработчики 404 и 500 — но вам все равно нужен токен CSRF в форме.
Незащищенному представлению нужен токен 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_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) уязвимостью? ¶
Нет, это сделано намеренно. Без атаки типа «человек посередине» злоумышленник не сможет отправить файл cookie с токеном CSRF в браузер жертвы, поэтому для успешной атаки потребуется получить файл cookie браузера жертвы с помощью XSS или аналогичного средства, и в этом случае злоумышленнику обычно не нужны CSRF-атаки.
Некоторые инструменты аудита безопасности отмечают это как проблему, но, как упоминалось ранее, злоумышленник не может украсть файл cookie CSRF браузера пользователя. «Кража» или изменение вашего собственного токена с помощью Firebug, инструментов разработчика Chrome и т. Д. Не является уязвимостью.
Проблема в том, что защита Django от CSRF по умолчанию не связана с сеансом? ¶
Нет, это сделано намеренно. Отсутствие привязки защиты CSRF к сеансу позволяет использовать защиту на таких сайтах, как pastebin, которые позволяют отправлять сообщения от анонимных пользователей, у которых нет сеанса.
Если вы хотите сохранить токен CSRF в сеансе пользователя, используйте CSRF_USE_SESSIONS параметр.
Почему пользователь может столкнуться с ошибкой проверки CSRF после входа в систему? ¶
По соображениям безопасности токены CSRF меняются каждый раз, когда пользователь входит в систему. Любая страница с формой, созданной до входа в систему, будет иметь старый, недопустимый токен CSRF, и ее необходимо будет перезагрузить. Это может произойти, если пользователь нажмет кнопку «Назад» после входа в систему или войдет в другую вкладку браузера.
Как использовать защиту Django CSRF
Чтобы воспользоваться защитой CSRF в своих представлениях, выполните следующие действия:
- Промежуточное ПО CSRF активируется по умолчанию в настройке MIDDLEWARE . Если вы переопределите этот параметр, помните, что ‘django.middleware.csrf.CsrfViewMiddleware’ должен стоять перед любым промежуточным программным обеспечением представления, которое предполагает, что атаки CSRF были обработаны. Если вы отключили его, что не рекомендуется, вы можете использовать csrf_protect() для определенных представлений, которые вы хотите защитить (см. below).
- В любом шаблоне, который использует POST form, используйте тег csrf_token внутри элемента , если form предназначен для внутреннего URL,, например:
form method=«post»>
Использование защиты CSRF с AJAX
Хотя описанный выше метод можно использовать для AJAX POST requests, он имеет некоторые неудобства: вы должны помнить о передаче токена 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 для своих представлений, как описано выше.
Файл 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(); // Начинается ли эта строка cookie с имени, которое нам нужно? if (cookie.substring(0, name.length + 1) === (name + '=')) < cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; > > > return cookieValue; > const csrftoken = getCookie('csrftoken');
Приведенный выше код можно упростить, используя JavaScript Cookie library вместо getCookie :
const csrftoken = Cookies.get('csrftoken');
Токен CSRF также присутствует в DOM в замаскированном form, но только в том случае, если он явно включен в шаблон с помощью csrf_token . Файл cookie содержит канонический токен без маски. CsrfViewMiddleware тоже примет. Однако для защиты от атак BREACH рекомендуется использовать замаскированный токен.
Если ваше представление не отображает шаблон, содержащий тег шаблона csrf_token , Django может не установить файл cookie токена CSRF. Это распространено в случаях, когда формы динамически добавляются на страницу. Чтобы решить эту проблему, Django предоставляет декоратор представления, который принудительно устанавливает файл cookie: ensure_csrf_cookie() .
Получение токена, если CSRF_USE_SESSIONS или CSRF_COOKIE_HTTPONLY равно True
Если вы активируете CSRF_USE_SESSIONS или CSRF_COOKIE_HTTPONLY , вы должны включить токен CSRF в свой HTML и прочитать токен из DOM с помощью JavaScript:.
script> const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value; script>
Установка токена на запрос AJAX
Наконец, вам нужно установить заголовок в запросе AJAX. Использование fetch() API:
const request = new Request( /* Т135048Т */, < method: 'POST', headers: 'X-CSRFToken': csrftoken>, mode: 'same-origin' // Не отправлять токен CSRF на другой домен. > ); fetch(request).then(function(response) < // . >);
Использование защиты CSRF в шаблонах Jinja2
Серверная часть шаблона Jinja2 Django добавляет > в контекст всех шаблонов, что эквивалентно в языке шаблонов Django. Например:
form method="post">>
Использование метода декоратора
Вместо того, чтобы добавлять CsrfViewMiddleware в качестве общей защиты, вы можете использовать декоратор csrf_protect() , который имеет точно такую же функциональность, для определенных представлений, которые нуждаются в защите. Его необходимо использовать как на представлениях, которые вставляют в вывод токен CSRF, так и на тех, которые принимают данные POST form. (These часто являются одной и той же функцией просмотра, но не always)..
Использование декоратора само по себе не рекомендуется, так как если вы забудете его использовать, у вас будет дыра в безопасности. Стратегия «пояса и подтяжек» с использованием обоих вариантов хороша и потребует минимальных накладных расходов.
Обработка отклонения requests
По умолчанию пользователю отправляется ответ «403 Forbidden», если входящий запрос не проходит проверку performed by CsrfViewMiddleware . Обычно это следует видеть только в случае подлинной подделки межсайтового запроса или когда из-за ошибки программирования токен CSRF не был включен в POST form.
Страница ошибки, однако, не очень удобна, поэтому вы можете предоставить собственное представление для обработки этого состояния. Для этого установите параметр CSRF_FAILURE_VIEW .
Ошибки CSRF регистрируются как предупреждения в регистраторе django.security.csrf .
Использование защиты CSRF с кэшированием
Если тег шаблона csrf_token используется шаблоном (или функция get_token вызывается каким-либо другим way),, CsrfViewMiddleware добавит в ответ файл cookie и заголовок Vary: Cookie . Это означает, что промежуточное ПО будет хорошо работать с промежуточным ПО кэша, если оно используется в соответствии с инструкциями ( UpdateCacheMiddleware предшествует всем остальным middleware).
Однако если вы используете декораторы кеша для отдельных представлений, промежуточное ПО 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): .
Если вы используете представления на основе классов, вы можете обратиться к Decorating class-based views .
Тестирование и защита CSRF
CsrfViewMiddleware обычно будет большим препятствием для тестирования функций представления из-за необходимости токена CSRF, который должен отправляться с каждым запросом POST. По этой причине клиент Django HTTP для тестов был изменен, чтобы установить флаг на requests, который расслабляет промежуточное программное обеспечение и декоратор csrf_protect , чтобы они больше не отклоняли requests. Во всем остальном (e.g. отправка файлов cookie etc.), ведут себя одинаково.
Если по какой-то причине вы хотите, чтобы тестовый клиент выполнял проверки CSRF, вы можете создать экземпляр тестового клиента, который принудительно выполняет проверки CSRF:
>>> from django.test import Client >>> csrf_client = Client(enforce_csrf_checks=True)
Edge cases
У некоторых представлений могут быть необычные требования, которые означают, что они не соответствуют обычному шаблону, описанному здесь. В таких ситуациях может пригодиться ряд утилит. Сценарии, в которых они могут понадобиться, описаны в следующем разделе.
Отключение защиты CSRF всего за несколько просмотров
Для большинства представлений требуется защита CSRF, но для некоторых нет.
Решение: вместо того, чтобы отключать промежуточное ПО и применять csrf_protect ко всем представлениям, которые в нем нуждаются, включите промежуточное ПО и используйте csrf_exempt() .
Установка токена, когда CsrfViewMiddleware.process_view() не используется
Бывают случаи, когда CsrfViewMiddleware.process_view может не запускаться до запуска вашего представления — например, обработчики 404 и 500 — но вам все равно нужен токен CSRF в form.
Включение токена CSRF в незащищенное представление
Некоторые представления могут быть незащищенными и исключены csrf_exempt , но все же должны включать токен CSRF.
Решение: используйте csrf_exempt() , а затем requires_csrf_token() . (i.e. requires_csrf_token должен быть самым внутренним decorator).
Защита представления только для одного пути
Представление нуждается в защите 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 form
Страница отправляет запрос POST через AJAX,, и на странице нет HTML form с csrf_token , который привел бы к отправке требуемого файла cookie CSRF.
Решение: используйте ensure_csrf_cookie() в представлении, которое отправляет страницу.
Защита CSRF в многоразовых приложениях
Поскольку разработчик может отключить CsrfViewMiddleware , все соответствующие представления в приложениях contrib используют декоратор csrf_protect для обеспечения безопасности этих приложений от CSRF.. Разработчикам других повторно используемых приложений, которым нужны такие же гарантии, также рекомендуется использовать декоратор csrf_protect в своих представлениях.