что такое csrf атака
Межсайтовая подделка запроса: защита от CSRF атак
Авторизуйтесь
Межсайтовая подделка запроса: защита от CSRF атак
CSRF (межсайтовая подделка запросов) — это вид атаки на сайт, которая производится с помощью мошеннического сайта или скрипта, который заставляет браузер пользователя выполнить нежелательное действие на доверенном сайте, на котором пользователь авторизован.
Обычно для этого пользователь должен перейти по мошеннической ссылке (которая может быть изменена с помощью сокращателя ссылок).
Например Джейн, авторизованная на сайте банка, проверяет свою почту. Она может перейти по фишинговой ссылке, которая включает запрос на перевод денег на аккаунт мошенника.
Благодаря тому, что она авторизована на сайте банка, тот обработает запрос на перевод.
Какие HTTP запросы подвержены CSRF атаке?
Методы GET, HEAD, OPTIONS и TRACE не подвержены CSRF, потому что предназначены только для получения информации и не изменяют состояние сервера.
Методы POST, PUT, DELETE и PATCH должны быть защищены от CSRF.
Cookies сессии
Cookies сессии — это способ, которым протокол HTTP отслеживает состояние. Веб-сайты используют cookies для идентификации пользователей и сохранения их данных.
После сохранения cookies, браузер отправляет их на сервер с каждым запросом, чтобы идентифицировать пользователя.
Злоумышленник может использовать cookies, чтобы выдать себя за пользователя, заставив браузер пользователя выполнить запрос.
Если пользователь уже вошел на сайт, cookies будут отправлены автоматически вместе с запросом.
Как работает межсайтовая подделка запросов?
Для того, чтобы злоумышленник осуществил атаку CSRF, нужны определённые условия:
CSRF могут быть подвергнуты веб-приложения использующие cookies, браузерную аутентификацию или клиентские сертификаты авторизации. По сути, CSRF подвержены все веб-приложения, которые автоматически добавляют аутентификационные данные пользователя к запросу.
Либо нужно начать с того, что злоумышленник обманом заставит жертву загрузить или отправить информацию в веб-приложение. Это может произойти несколькими способами – например, через фишинговую ссылку.
Эксплойт может быть замаскирован под обычную ссылку или скрыт в теге изображения.
Вот пример атаки через обычную ссылку:
Или через тэг изображения:
Способы защиты от CSRF атак
Выбор защищённых фреймфорков
Anti-CSRF токены
Токены (или synchronizer token) — это способ защиты со стороны сервера. Сервер генерирует случайный уникальный токен для браузера пользователя и проверяет его для каждого запроса.
Токен находится в скрытом поле, должен быть непредсказуемым случайным числом и иметь небольшое время жизни, без возможности переиспользования.
Токен должен удовлетворять следующим условиям:
Использование двух токенов
Смысл этого метода в том, что используются два токена: первый сохраняется в cookies, а второй — в одном из параметров ответа.
В таком случае сервер, получая один из небезопасных запросов, должен проверить оба токена.
Использование флага Same-Site в сookies
Этот флаг помечает куки для определенного домена.
Таким образом проверяется источник запроса, и его не получится выполнить с мошеннического сайта.
Этот флаг поддерживает большинство браузеров. Его стоить использовать как часть общей стратегии защиты от CSRF атак.
Требуйте подтверждения от пользователя
Для чувствительных действий, вроде перевода денег или смены пароля, требуйте дополнительное действие от юзера (ввод капчи или кода подтверждения).
XSS- и CSRF-атаки — разбираем уязвимости
Авторизуйтесь
XSS- и CSRF-атаки — разбираем уязвимости
Noveo Developer
В контексте веб-безопасности есть два основных вектора атаки, которые необходимо учитывать: XSS и CSRF. Прежде чем рассказать о них, необходимо понимать дефолтную политику браузера насчёт взаимодействия между вкладками — точнее, взаимодействия между скриптами с разным origin’ами. Эта политика называется Same Origin Policy (SOP). Её центральное понятие — Origin (
источник) скрипта/документа. Он определяется комбинацией трёх понятий: протокола (http/https, etc.), хоста (my-website.com) и порта (например, 443 для https и 80 для http).
Вот примеры, которые браузер будет интерпретировать как скрипты с одинаковым origin’ом. Если на открытой вкладке присутствует 3 скрипта, origin’ы которых отличаются подобным образом, то браузер будет воспринимать их как скрипты с одним origin’ом:
А такие origin’ы будут считаться разными:
Важная особенность SOP: скрипт с одним origin’ом может посылать запросы на другой origin. Однако не сможет прочитать ответ на него. Чтение ответа будет заблокировано на уровне браузера. Если требуется заблокировать в том числе отправку запросов (скажем, вы не хотите, чтобы скрипты, загруженные на вашем сайте с других origin’ов, могли делать запрос на origin сайта), это тоже возможно реализовать посредством указания Content Security Policy. Но дефолтная политика (SOP) работает именно так.
XSS / JS-Injections
Наиболее часто встречающейся атакой является Cross-Site Scripting («Межсайтовый скриптинг»), или более удачное, на мой взгляд, название — JS-инъекции (по аналогии с SQL-инъекциями). Если в html-документ вставить строку, в которой будут использоваться элементы, похожие на html-теги, то браузер будет интерпретировать их как валидный html-код и исполнять его. Например, можно прописать с пустым src и добавить onerror=“alert(‘hacked’)” (так как src пустой, то браузер сразу перейдет к вызову onerror), внутри которого выполнить любой JS-код (имея доступ к localStorage и так далее). Также можно поместить вредоносный скрипт внутрь запроса query params в следующем виде:
Предотвращение JS-инъекций
В современных фреймворках (вроде Angular/React) изначально действует санитизация, которую в случае необходимости (если вы хотите запустить inline-скрипт из строки и уверены, что там не содержится ничего вредоносного) можно отключить. В React’е это делается посредством атрибута, подчеркивающего опасность вставки inline-скриптов:
В Angular’е можно за’inject’ить санитайзер и выбрать тот уровень санитизации, который подходит под ситуацию. Например, можно разрешить чтение стилей, но при этом экранировать любые скрипты.
Помимо санитизации существует Content Security Policy (CSP) Header. Через него можно явно задать, скрипты с каким origin’ом могут исполняться браузером на текущей странице. По дефолту Content Security Policy содержит значение *. То есть браузеру разрешено запускать скрипты с любым origin’ом, включая inline-скрипты без origin’а. Такие настройки считаются очень небезопасными, и рекомендуется всегда явно указывать, скрипты с каким origin’ом можно запустить на сайте. Явное указание ограниченного набора origin’ов заодно предотвращает исполнение inline-скриптов. Чтобы разрешить их исполнение, требуется явно это прописывать.
Пример того, как может выглядеть CSP Header:
Такие настройки означают, что изображения могут подгружаться с любого источника (*), media только с двух источников (media1.com & media2.com). А скриптам позволено запускаться, если они имеют только один origin (userscripts.example.com). default-src ‘self’ позволяет запускать скрипты с текущего origin’а, но не его поддоменов.
4–5 декабря, Онлайн, Беcплатно
Посредством CSP-заголовка можно очень тонко настраивать исполнение скриптов на сайте.
content-security-policy Header и access-control-allow-origin немного похожи. CSP позволяет обходить SOP, а access-control-allow-origin позволяет получать разрешение на CORS. То есть отвечать (response) на запросы скриптов с другим origin’ом.
В начале статьи я упоминал, что SOP позволяет скриптам с одним origin’ом делать запросы на другой origin, однако SOP заблокирует ответ. Посредством access-control-allow-origin можно получить доступ к этому ответу, если на сервере явно прописан origin, который имеет право получать ответы.
Если кратко и утрированно, то SCP — это про SOP и frontend-часть системы. А access-control-allow-otigin — про CORS и backend-часть.
CSRF (XSRF)
Второй по распространённости тип уязвимости — это Cross-Site Request Forgery («Межсетевая подделка запроса»). Этот вектор атаки использует склонность браузера неявно добавлять куки к любому запросу. Например, вы авторизовались на сайте, где используются куки, и в какой-то момент некий скрипт делает запрос на origin этого банка — то есть открыли почтовый клиент и перешли по вредоносной ссылке. Браузер автоматически добавит куки к запросу, даже если сам запрос происходит с другой вкладки.
Из-за SOP этот скрипт не будет иметь доступа к response. Но он сможет выполнять запросы на правах авторизованного пользователя. Например, сделать запрос на перевод денег или просто на удаление любой возможной информации.
Для предотвращения этой атаки в первую очередь рекомендуется использовать явные системы аутентификации. Например, session token / jwt в header или session token в body param. Также, если на сайте используется какая-то форма, то рекомендуется реализовывать anti-csrf token’ы. Их суть в том, что сервер в response отдаёт два случайных токена. Один предназначен для куков, другой прячется в скрытом поле формы. Когда клиент submit’ит форму, то должен отправить оба токена обратно на сервер. В случае, если они отличаются от того, что сервер выпустил изначально, сервер блокирует запрос.
Integrity
В контексте информационной безопасности существует понятие CIA triad, объединяющее три аспекта:
В web’е это можно представить в виде отношений между frontend’ом и backend’ом. В html есть специальный атрибут integrity, позволяющий запускать скрипт только в том случае, если он не отличается от того, что изначально подразумевали его разработчики.
Предположим, что вы используете cdn (content delivery network) для оптимизации скорости доставки приложения, однако вы хотите быть уверены, что приложение, которое вы сбилдили сами, и то, которое получаете из cdn, — одно и то же. В этом случае можно в процессе прод-билда приложения сгенерировать integrity-хеш, который указывается следующим образом:
Атака CSRF
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Нельзя говорить про AJAX и не упомянуть про важнейшую деталь его реализации – защиту от CSRF-атак.
CSRF (Cross-Site Request Forgery, также XSRF) – опаснейшая атака, которая приводит к тому, что хакер может выполнить на неподготовленном сайте массу различных действий от имени других, зарегистрированных посетителей.
Какие это действия – отправка ли сообщений, перевод денег со счёта на счёт или смена паролей – зависят от сайта, но в любом случае эта атака входит в образовательный минимум веб-разработчика.
Злая форма
«Классический» сценарий атаки таков:
Вася попал на «злую страницу», например хакер пригласил его сделать это письмом или как-то иначе.
На злой странице находится форма такого вида:
Сайт mail.com проверяет куки, видит, что посетитель авторизован и обрабатывает форму. В данном примере форма предполагает посылку сообщения.
Итог атаки – Вася, зайдя на злую страницу, ненароком отправил письмо от своего имени. Содержимое письма сформировано хакером.
Защита
В примере выше атака использовала слабое звено авторизации.
Куки позволяют сайту mail.com проверить, что пришёл именно Вася, но ничего не говорят про данные, которые он отправляет.
Иначе говоря, куки не гарантируют, что форму создал именно Вася. Они только удостоверяют личность, но не данные.
Типичный способ защиты сайтов – это «секретный ключ» ( secret ), специальное значение, которое генерируется случайным образом при авторизации и сохраняется в сессии посетителя. Его знает только сервер, посетителю мы его даже не будем показывать.
Разумеется, для разных посетителей secret будет разным.
Формула вычисления токена:
Далее, токен добавляется в качестве скрытого поля к каждой форме, генерируемой на сервере.
Такой токен также называют «подписью» формы, которая удостоверяет, что форма сгенерирована именно на сервере.
Эта подпись говорит о том, что автор формы – сервер, но ничего не гарантирует относительно её содержания.
Есть ситуации, когда мы хотим быть уверены, что некоторые из полей формы посетитель не изменил самовольно. Тогда мы можем включить в MD5 для формулы токена эти поля, например:
Токен и AJAX
Теперь перейдём к AJAX-запросам.
Что если посылка сообщений в нашем интерфейсе реализуется через XMLHttpRequest?
Как и в случае с формой, мы должны «подписать» запрос токеном, чтобы гарантировать, что его содержимое прислано на сервер именно интерфейсом сайта, а не «злой страницей».
Здесь возможны варианты, самый простой – это дополнительная кука.
Код, осуществляющий XMLHttpRequest, получает куку и ставит заголовок X-CSRF-TOKEN с ней:
Сервер проверяет, есть ли заголовок и содержит ли он правильный токен.
Защита действует потому, что прочитать куку может только JavaScript с того же домена. «Злая страница» не сможет «переложить» куку в заголовок.
Если нужно сделать не XMLHttpRequest, а, к примеру, динамически сгенерировать форму из JavaScript – она также подписывается аналогичным образом, скрытое поле или дополнительный URL-параметр генерируется по куке.
Итого
CSRF-атака – это когда «злая страница» отправляет форму или запрос на сайт, где посетитель, предположительно, залогинен.
Если сайт проверяет только куки, то он такую форму принимает. А делать это не следует, так как её сгенерировал злой хакер.
Для подписи XMLHttpRequest токен дополнительно записывается в куку. Тогда JavaScript с домена mail.com сможет прочитать её и добавить в заголовок, а сервер – проверить, что заголовок есть и содержит корректный токен.
Динамически сгенерированные формы подписываются аналогично: токен из куки добавляется как URL-параметр или дополнительное поле.
Национальная библиотека им. Н. Э. Баумана
Bauman National Library
Персональные инструменты
CSRF (Сross Site Request Forgery)
Содержание
Пример
Рассмотрим пример базовой CSRF уязвимости, чтобы понять ее принцип. В качестве примера, возьмем Low Level CSRF в веб-приложении DVWA. Откроем страницу. Используем кольцевой адрес в качестве proxy, запустим Burp, который будет использовать кольцевой адрес для перехвата и модификации запросов. Посмотрим, что же происходит.
Для начала откроем страницу и посмотрим код.
Результат следующий:
Попробуем поменять пароль:
Проведем самую простую CSRF атаку.
Отправим цели следующую ссылку: http://192.168.56.101/crackit/dvwa/vulnerabilities/csrf/?password_new=hacked&password_conf=hacked&Change=Change
При переходе по этой ссылке, пользователь, имеющий сессию на сервере поменяет свой пароль на hacked.
Другой способ: можем поднять сервер, после чего создать там следующую html страницу:
Перейдя на такую страницу, браузер пользователя попытается подгрузить картинку, а значит перейдет по ссылке, после чего пароль поменяется на hacked.
В обоих случаях итог следующий:
Это и был пример простейшей CSRF атаки.
Защита от CSRF
Это значение – с одной стороны, случайное, с другой – имея такой token, мы можем взять его первую часть 1234 в качестве salt и, зная secret, проверить по формуле, верно ли он вычислен. Не зная secret, невозможно сгенерировать token, который сервер воспримет как правильный. Далее, токен добавляется в качестве скрытого поля к каждой форме, генерируемой на сервере. То есть, «честная» форма для отсылки сообщений, созданная на http://mail.com, будет выглядеть так:
При её отправке сервер проверит поле csrf, удостоверится в правильности токена, и лишь после этого отошлёт сообщение. «Злая страница» при всём желании не сможет сгенерировать подобную форму, так как не владеет secret, и токен будет неверным. Такой токен также называют «подписью» формы, которая удостоверяет, что форма сгенерирована именно на сервере.
Подпись с полями формы
Использование AJAX
Теперь перейдём к AJAX-запросам.
Что если посылка сообщений в нашем интерфейсе реализуется через XMLHttpRequest?
Как и в случае с формой, мы должны «подписать» запрос токеном, чтобы гарантировать, что его содержимое прислано на сервер именно интерфейсом сайта, а не «злой страницей».
Здесь возможны варианты, самый простой – это дополнительная кука.
Защита действует потому, что прочитать куку может только JavaScript с того же домена. «Злая страница» не сможет «переложить» куку в заголовок.
Если нужно сделать не XMLHttpRequest, а, к примеру, динамически сгенерировать форму из JavaScript – она также подписывается аналогичным образом, скрытое поле или дополнительный URL-параметр генерируется по куке.
CSRF-уязвимости все еще актуальны
CSRF (Сross Site Request Forgery) в переводе на русский — это подделка межсайтовых запросов. Михаил Егоров (0ang3el) в своем докладе на Highload++ 2017 рассказал о CSRF-уязвимостях, о том, какие обычно используются механизмы защиты, а также как их все равно можно обойти. А в конце вывел ряд советов о том, как правильно защищаться от CSRF-атак. Под катом расшифровка этого выступления.
О спикере: Михаил Егоров работает в компании Ingram Micro Cloud и занимается Application security. В свободное время Михаил занимается поиском уязвимостей и Bug hunting и выступает на security-конференциях
Дисклаймер: приведенная информация является сугубо мнением автора, все совпадения случайны.
В том, что CSRF-атаки работают виноват этот Cookie-монстр. Дело в том, что многие веб-приложения используют куки (здесь и далее считаем уместным называть cookies по-русски) для управления сессией пользователя. Браузер устроен так, что, если у него есть куки пользователя для данного домена и пути, он их автоматически отправляет вместе с HTTP-запросом.
Cookies
Куки — это небольшой фрагмент данных, который веб-сервер отправляет клиенту в виде name=value в HTTP-заголовке c названием «Set-Cookie». Браузер хранит эти данные на компьютере пользователя, и всякий раз при необходимости пересылает этот фрагмент данных веб-серверу в составе HTTP-запроса в HTTP-заголовке с названием «Cookie».
Куки могут иметь различные атрибуты, такие как: expires, domain, secure, httponly:
Впервые куки появились в браузере Netscape в далеком 1994 году. До сих пор многие веб-приложения используют их для управления сессией пользователя.
Рассмотрим, как работает классическая Сross Site Request Forgery (CSRF) атака.
Допустим, в нашем веб-приложении есть возможность изменять адрес доставки у пользователя, и оно использует куки для управления сессией.
У нас есть HTML-форма, которую пользователь должен заполнить: ввести адрес и нажать кнопку «Сохранить». В результате в бэкенд полетит POST-запрос с HTML-формой. Мы видим, что браузер автоматически поставил туда сессионные куки пользователя. Бэкенд, когда получит такой запрос, посмотрит, что есть такая сессия, это легитимный пользователь, и изменит ему адрес доставки.
Что может сделать атакующий?
Он может на своем сайте attacker.com разместить такую HTML-страничку, которая на самом деле сабмитит HTML-форму на сайт example.com. Так как браузер автоматически вставляет куки пользователя в HTTP-запрос, то бэкенд просто не поймет, является ли данный запрос легитимным — результат ли это заполнения формы пользователем, или это CSRF-атака — и поменяет адрес доставки для пользователя на значение, которое выгодно для атакующего.
Есть другой вариант CSRF-атаки с использованием XHR API. Если о CSRF-атаке с использованием HTML-форм слышали многие, то о данном способе знают меньше, но он тоже работает.
Обратите внимание на атрибут withCredentials, который заставляет браузер автоматически отправлять куки пользователя. Так как значение Content-type равно application/x-www-form-urlencoded, то браузер данный запрос отправит без CORS options preflight request, и опять CSRF-атака будет работать.
Рассмотрим более наглядно, как это происходит.
История CSRF-атак
Вообще о CSRF-атаках известно с 2001 года, когда их начали активно эксплуатировать. В период 2008-2012 такие уязвимости были на каждом первом сайте, в том числе:
Насколько серьезны CSRF-уязвимости?
На самом деле, все зависит от критичности уязвимого действия. Это может быть:
В проекте OWASP Top 10, который содержит 10 наиболее критичных уязвимостей в приложении, в 2010 году CSRF-уязвимости находились на 5 месте. Потом разработчики начали имплементировать различные варианты защиты и уже в 2013 году CSRF-уязвимости сместились на 8 позицию.
В список за 2017 год CSRF-уязвимости вообще не вошли, потому что якобы по статистике сейчас при penetration-тестировании они находятся только в 8% случаев.
Лично я не согласен с данной статистикой, потому что буквально за последние два года находил много CSRF-уязвимостей. Дальше я расскажу, как я это делал.
В классификации Bugcrowd VRT (Vulnerability Rating Taxonomy) Application-wide CSRF-уязвимости имеют рейтинг severity P2 (High). Выше только severity critical, то есть это достаточно серьезные уязвимости.
Рассмотрим, какие варианты защиты от CSRF существуют и как работает каждый из вариантов защиты.
Поэтому, теперь давайте поговорим о 8 способах обхода защиты, которые можно использовать на практике.
Сценарии обхода:
1. XSS (cross-sitescripting)
Если в вашем веб-приложении есть XSS, то это автоматически делает его уязвимым к CSRF, и от этого сложно защититься. Можно только смириться.
2. Dangling markup
Допустим, в нашем приложении есть уязвимость к HTML injection, но нет XSS. Например, есть Content Security Policy (CSP), которая защищает от XSS. Но атакующий все равно может внедрять HTML теги.
Если в нашем приложении реализована защита, основанная на CSRF-токенах, атакующий может внедрить такой HTML, это не закрытые теги image или form:
В результате часть DOM HTML страницы будет отправлена на ресурс атакующего. Высока вероятность того, что если атакующий правильно внедрит такой HTML, тогда то, что придет на сайт атакующего, будет содержать CSRF-токен.
Таким образом узнав токен, атакующий сможет эксплуатировать CSRF классическим способом.
3. Уязвимый субдомен
Допустим, у нас есть субдомен foo.example.com, и он уязвим к subdomain takeover или XSS. В результате subdomain takeover, атакующий полностью контролирует субдомен и может добавлять туда любые HTML-странички или выполнять JS-код в контексте субдомена. Если наш субдомен уязвим к таким вещам, то атакующий сможет обойти следующие типы CSRF-защиты:
Следующий вариант. Допустим, на основном домене, который мы хотим атаковать, есть файл crossdomain.xml. Этот файл используется flash- и PDF-плагинами для субдоменного взаимодействия, и к нему разрешен доступ с любых субдоменов.
Если атакующий может загрузить JS-файл на foo.example.com, то в этом случае он может использовать Service Worker API для субдомена foo.example.com, который на самом деле отдает flash-файл.
Так как у нас есть crossdomain.xml на основном домене, который разрешает взаимодействие субдоменов, то атакующий через этот SWF просто читает CSRF токен.
Кстати, подобная уязвимость недавно была найдена в Amazon, подробнее здесь.
Даже если не сконфигурирован CORS и нет файла crossdomain.xml, но используется защита Double submit cookie, атакующий может просто вставлять куки с субдомена для родительского домена на путь, где он хочет эксплуатировать CSRF, и таким образом обойти Double submit cookie защиту.
4. Bad PDF
Этот сценарий обхода основан на PDF. В Adobe есть PDF плагин, который автоматически устанавливается при установке Adobe Reader. Этот плагин поддерживает так называемый FormCalc скрипт. Правда, сейчас PDF плагин от Adobe работает только в IE11 и Firefox ESR.
В FormCalc есть два замечательных метода: get() и post(). Атакующий с помощью метода get может прочитать CSRF токен, с помощью post отправить к себе на сайт. Так атакующий получает CSRF-токен жертвы.
Допустим, у нас есть возможность загрузить PDF-файл в веб-приложение. На самом деле это может быть даже файл другого формата, например, атакующий может попытаться загрузить PDF под видом картинки, которая является аватаром пользователя.
У приложения есть некоторый API на основном домене, который позволяет получать содержимое загруженного файла. Тогда атакующий может использовать такую HTML страничку, которая с помощью тега embed встраивает PDF-файл, который атакующий загрузил на example.com.
Файл leak.pdf:
Этот файл содержит FormCalc скрипт, который как раз читает страницу Settings.action, где в DOM есть CSRF токен и отправляет с помощью метода post на сайт атакующего.
Дополнительный фокус в том, что для PDF плагина не важно, с каким Content-Type отдается PDF-файл, и даже в HTTP-ответе могут присутствовать другие заголовки (например, Content-Disposition). PDF плагин все равно будет рендерить этот PDF и выполнять FormCalc скрипт.
5. Cookie injection
Если используется Double submit cookie защита, то если атакующий сможет каким-либо образом внедрить куки, то это game over.
Один из наиболее популярных вариантов в этом сценарии — это CRLFinjection.
Если атакующий может вставлять в ответ сервера дополнительные заголовки, то он просто может добавить заголовок Set-Cookie с нужными куками и обойти CSRF-защиту.
Другой вариант связан с особенностями обработки куков браузером.
Например, в Safari можно через запятую вставлять новые куки (comma-separated cookies). Допустим, у нас есть URL-параметр в заголовке с именем language. Мы его обрабатываем и записываем пользователю в куки выбранное значение language. Если атакующий вставит запятую, то он может вставить и дополнительные куки с любым именем.
Также в обходе CSRF-защиты могут посодействовать баги браузера. Например, в Firefox была возможность внедрять куки через SVG-картинку (CVE-2016-9078). Если у нас есть HTML-редактор и мы разрешаем пользователю вставлять image-теги, то атакующий может просто в SRC-атрибуте указать на SVG-картинку, которая установит нужные куки.
6. Change Content-Type
Некоторые разработчики считают, что если используется нестандартный формат данных в теле POST-запроса для общения с бэкендом, то это может спасти от CSRF. На самом деле это не так.
В качестве примера приведу уязвимость, которую я недавно нашел в одном очень популярном сервисе по управлению заметками.
Там использовался API, который использует Apache Thrift (бинарный формат данных) и куки для управления сессией. Допустим, чтобы добавить новую заметку, пользователь должен был отправить такой POST-запрос. В теле передавались бинарные данные и указывался Content-Type: application/x-thrift.
На самом же деле в бэкенде этот Content-Type не валидировался. Можно было его поменять на text/plain и с помощью XHR API эксплуатировать эту CSRF-уязвимость, просто передав бинарные данные в теле POST-запроса.
На самом деле защита, основанная на Content-Type — это очень плохой вариант защиты. Он в большинстве случаев обходится.
7. Non-simple Content-Type
Через HTML-форму или с помощью XHR API мы можем отправить следующие content types:
Довольно известный баг в браузере Chrome был найден в 2015 году, после этого примерно через месяц попал в публичный доступ, но был исправлен только в 2017 году. Этот баг позволял отправлять POST-запрос с любым Content-Type на другой origin с помощью API, которое называется Navigator.sendBeacon().
Как выглядела эксплуатация?
Мы создаем новый blob с нужным Content-Type и просто отправляем его с помощью Navigator.sendBeacon().
Еще один сценарий обхода, который до сих пор работает и поддерживается в браузерах — обход с помощью flash-плагина.
Даже есть сайт thehackerblog.com, где уже есть готовая флэшка, вы просто указываете URL, header, нужный Content-Type и данные, которые надо передать — отправляете, и в бэкенд улетает POST-запрос с нужным Content-Type.
Но есть одна хитрость — нельзя просто указать URL сайта, который мы атакуем. Нужно указать ресурс, который сделает redirect с кодом 307 на ресурс, который мы атакуем. Тогда это будет работать.
8. Spoof Referer
Последний вариант обхода защиты от CSRF основан на Referer. Есть баг в Microsoft Edge браузере, который до сих пор не исправлен и позволяет подделывать значение Referer. Но он работает, к сожалению, только для GET-запросов. Если атакуемый бэкенд не отличает GET от POST, то этот баг можно эксплуатировать.
Если все же нам надо POST, то есть небольшая хитрость. Мы можем отправить header Referer с помощью PDF плагина и FormCalc.
Где-то год назад можно было с помощью PDF плагина отправлять вообще любые header’ы, в том числе host, но потом Adobe закрыл эту возможность создав черный список header’ов. То есть если мы укажем Referer в заголовке, то этот заголовок просто не отправится.
Вообще FormCalc позволяет нам легально отправлять любой Content-Type. Если мы будем вставлять символы carridge return и line feed, то сможем добавлять в запрос дополнительные header’ы.
Это итоговая таблица. В столбцах представлены варианты защиты от CSRF, а в строках — методы обхода. В каждой ячейке указаны браузеры, в которых работает этот метод:
Наиболее кардинальный и работающий вариант защититься от CSRF-атак — это избавиться от куков и использовать header с токенами.
Но если вы все-таки не готовы отказаться от куков для управления пользовательской сессией:
Не прошло и полугода, а следующий хайлоад уже через месяц — Highload++ Siberia.
Хотим привлечь ваше внимание к некоторым из отобранных докладов: