CSRF: Обход ограничений SameSite cookie-файлов

Источник: «Bypassing SameSite cookie restrictions»
SameSite — это механизм защиты браузера, определяющий, когда файлы cookie сайта включаются в запросы, поступающие с других сайтов. Ограничения на использование файлов cookie SameSite обеспечивают частичную защиту от различных межсайтовых атак, включая CSRF, межсайтовые утечки и некоторые CORS-эксплойты.

Начиная с 2021 года Chrome по умолчанию применяет ограничения Lax SameSite, если сайт, на котором размещён файл cookie, не задал явно свой собственный уровень ограничений. Это предложенный стандарт, и мы ожидаем, что в будущем такое поведение будет реализовано и в других основных браузерах. Таким образом, для тщательного тестирования на наличие векторов межсайтовых атак необходимо иметь чёткое представление о том, как работают эти ограничения и как их можно обойти.

В этом разделе мы рассмотрим принцип работы механизма SameSite и поясним некоторые термины, связанные с ним. Затем мы рассмотрим наиболее распространённые способы обхода этих ограничений, позволяющие осуществлять CSRF и другие межсайтовые атаки на сайты, которые на первый взгляд кажутся безопасными.

Что такое сайт в контексте SameSite файлов cookie

В контексте ограничений на использование cookie-файлов SameSite под сайтом понимается домен верхнего уровня (TLD), обычно такой, как .com или .net, плюс один дополнительный уровень доменного имени. Это часто называют TLD+1.

При определении того, является ли запрос односайтовым или нет, учитывается также схема URL. Это означает, что ссылка с http://app.example.com на https://app.example.com большинством браузеров рассматривается как межсайтовая.

URL

Примечание. Вы можете встретить термин эффективный домен верхнего уровня (eTLD). Это всего лишь способ учёта зарезервированных многочастных суффиксов, которые на практике рассматриваются как домены верхнего уровня, например .co.uk.

В чем разница между сайтом и источником?

Разница между сайтами и источниками заключается в их масштабах: сайт включает в себя несколько доменных имён, в то время как источник — только одно. Несмотря на тесную взаимосвязь, важно не использовать эти термины как взаимозаменяемые, поскольку их смешение может иметь серьёзные последствия для безопасности.

Два URL-адреса считаются имеющими одинаковый источник, если у них одинаковая схема, доменное имя и порт. Хотя следует отметить, что порт часто определяется по схеме.

Разница между сайтом (site) и источником (origin)
Разница между сайтом (site) и источником (origin)

Как видно из этого примера, термин сайт гораздо менее конкретен, поскольку учитывает только схему и последнюю часть доменного имени. Это означает, что cross-origin запрос все ещё может быть same-site, но не наоборот.

Запрос отЗапрос кSame-site?Same-origin?
https://example.comhttps://example.comДаДа
https://app.example.comhttps://intranet.example.comДаНет: несоответствие доменного имени
https://example.comhttps://example.com:8080ДаНет: несоответствие порта
https://example.comhttps://example.co.ukНет: несоответствие eTLDНет: несоответствие доменного имени
https://example.comhttp://example.comНет: несоответствие схемыНет: несоответствие схемы

Это важное различие, поскольку оно означает, что любая уязвимость, позволяющая выполнить произвольный JavaScript, может быть использована для обхода защиты сайта на других доменах, принадлежащих тому же сайту.

Как работает SameSite?

До появления механизма SameSite браузеры отправляли файлы cookie в каждом запросе к выдавшему их домену, даже если запрос был вызван не связанным с ним сторонним сайтом. SameSite позволяет браузерам и владельцам сайтов ограничить, какие межсайтовые запросы, если таковые имеются, должны включать определённые файлы cookie. Это позволяет снизить подверженность пользователей CSRF-атакам, которые побуждают браузер жертвы отправить запрос, вызывающий вредоносное действие на уязвимом сайте. Поскольку для таких запросов обычно требуется файл cookie, связанный с аутентифицированной сессией жертвы, атака будет безуспешной, если браузер не включит его.

В настоящее время все основные браузеры поддерживают следующие уровни ограничений SameSite:

Разработчики могут вручную настроить уровень ограничения для каждого установленного cookie-файла, что даёт им больше возможностей для контроля над тем, когда эти cookie-файлы используются. Для этого достаточно включить атрибут SameSite в заголовок ответа Set-Cookie и указать желаемое значение:

Set-Cookie: session=0F8tgdOhi9ynR1M9wa3ODa; SameSite=Strict

Хотя это и обеспечивает некоторую защиту от CSRF-атак, ни одно из этих ограничений не даёт гарантированного иммунитета.

Примечание. Если сайт, выдающий cookie, явно не задал атрибут SameSite, Chrome по умолчанию автоматически применяет ограничения Lax. Это означает, что cookie будет отправляться только в межсайтовых запросах, удовлетворяющих определённым критериям, даже если разработчики не настраивали такое поведение. Поскольку это предложенный новый стандарт, мы ожидаем, что в будущем такое поведение будет реализовано и в других основных браузерах.

Strict

Если cookie установлен с атрибутом SameSite=Strict, браузеры не будут отправлять его при межсайтовых запросах. Проще говоря, это означает, что если целевой сайт запроса не совпадает с сайтом, отображаемым в данный момент в адресной строке браузера, то cookie не будет включён.

Это рекомендуется делать при установке cookies, позволяющих пользователю изменять данные или выполнять другие конфиденциальные действия, например, получать доступ к определённым страницам, которые доступны только аутентифицированным пользователям.

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

Lax

Ограничения Lax SameSite означают, что браузеры будут отправлять cookie при межсайтовых запросах, но только если выполняются оба следующих условия:

Это означает, что cookie не включается, например, в межсайтовые POST запросы. Поскольку POST запросы обычно используются для выполнения действий, изменяющих данные или состояние (по крайней мере, согласно лучшим практикам), они с гораздо большей вероятностью могут стать целью CSRF-атак.

Аналогичным образом cookie не включается в фоновые запросы, например, инициируемые скриптами, iframe или ссылками на изображения и другие ресурсы.

None

Если cookie установлен с атрибутом SameSite=None, то это фактически полностью отключает ограничения SameSite, независимо от браузера. В результате браузеры будут отправлять этот cookie во всех запросах к выдавшему его сайту, даже в тех, которые были вызваны совершенно несвязанными с ним сторонними сайтами.

За исключением Chrome, это поведение по умолчанию, используемое основными браузерами, если при установке cookie не указан атрибут SameSite.

Существуют обоснованные причины для отключения SameSite, например, когда файл cookie предназначен для использования в стороннем контексте и не предоставляет его носителю доступ к каким-либо конфиденциальным данным или функциональным возможностям. Типичным примером являются отслеживающие файлы cookie.

Если вы встретили файл cookie, установленный с параметром SameSite=None или без явных ограничений, стоит выяснить, насколько он полезен. Когда поведение Lax-by-default было впервые применено в Chrome, это привело к поломке многих существующих веб-функций. В качестве быстрого обходного пути некоторые сайты решили просто отключить ограничения SameSite для всех файлов cookie, включая потенциально важные.

При установке cookie с параметром SameSite=None веб-сайт должен также включать атрибут Secure, который гарантирует, что cookie будет отправляться только в зашифрованных сообщениях по протоколу HTTPS. В противном случае браузеры будут отклонять cookie, и он не будет установлен.

Set-Cookie: trackingId=0F8tgdOhi9ynR1M9wa3ODa; SameSite=None; Secure

Обход ограничений SameSite Lax с помощью GET-запросов

На практике серверы не всегда строго следят за тем, какой запрос — GET или POST — они получают к данной конечной точке, даже те, которые ожидают отправки формы. Если они также используют ограничения Lax для своих сессионных cookie-файлов, явно или по умолчанию в браузере, то вы все равно сможете провести CSRF-атаку, вызвав GET запрос из браузера жертвы.

До тех пор, пока в запросе присутствует навигация верхнего уровня, браузер будет включать сессионный cookie жертвы. Ниже приведён один из самых простых подходов к реализации такой атаки:

<script>
document.location = 'https://vulnerable-website.com/account/transfer-payment?recipient=hacker&amount=1000000';
</script>

Даже если обычный GET-запрос недопустим, некоторые фреймворки предоставляют возможность переопределить метод, указанный в строке запроса. Например, Symfony поддерживает параметр _method в формах, который имеет приоритет над обычным методом для целей маршрутизации:

<form action="https://vulnerable-website.com/account/transfer-payment" method="POST">
<input type="hidden" name="_method" value="GET">
<input type="hidden" name="recipient" value="hacker">
<input type="hidden" name="amount" value="1000000">
</form>

Другие фреймворки поддерживают целый ряд аналогичных параметров.

Обход ограничений SameSite с помощью гаджетов, установленных на сайте

Если cookie установлен с атрибутом SameSite=Strict, браузеры не будут включать его в межсайтовые запросы. Это ограничение можно обойти, если найти гаджет, который приводит к вторичному запросу в пределах одного сайта.

Одним из возможных гаджетов является редирект на стороне клиента, который динамически конструирует цель перенаправления, используя контролируемые злоумышленником входные данные, например параметры URL. Некоторые примеры приведены в наших материалах, посвящённых открытой переадресации на основе DOM.

С точки зрения браузеров, эти клиентские переадресации на самом деле не являются переадресациями; полученный запрос рассматривается как обычный, отдельный запрос. Самое главное, что это запрос на один сайт, и, следовательно, в него будут включены все файлы cookie, относящиеся к сайту, независимо от существующих ограничений.

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

Отметим, что аналогичная атака невозможна при перенаправлениях на стороне сервера. В этом случае браузеры понимают, что запрос на переадресацию изначально был межсайтовым, и применяют соответствующие ограничения на использование cookie.

Обход ограничений SameSite с помощью уязвимых дочерних доменов

Независимо от того, тестируете ли вы чужой сайт или пытаетесь защитить свой собственный, необходимо помнить, что запрос все равно может быть односайтовым, даже если он выдан по принципу cross-origin.

Обязательно проведите тщательный аудит всей доступной поверхности атаки, включая все дочерние домены. В частности, уязвимости, позволяющие вызвать произвольный вторичный запрос, такие как XSS, могут полностью скомпрометировать защиту сайта и подвергнуть все его домены межсайтовым атакам.

Помимо классического CSRF, не забывайте, что если целевой сайт поддерживает WebSockets, то эта функциональность может быть уязвима для межсайтового перехвата WebSocket (CSWSH), который, по сути, представляет собой CSRF-атаку, направленную на рукопожатие WebSocket. Более подробную информацию можно найти в нашей теме, посвящённой уязвимостям WebSocket.

Обход ограничений SameSite Lax с помощью новых файлов cookie

Cookies с ограничениями Lax SameSite обычно не пересылаются в межсайтовых POST-запросах, но есть и исключения.

Как уже говорилось, если сайт не включает атрибут SameSite при установке cookie, Chrome автоматически применяет ограничения Lax по умолчанию. Однако чтобы не нарушать механизмы единой авторизации (SSO), он не применяет эти ограничения в течение первых 120 секунд при POST-запросах верхнего уровня. В результате возникает двухминутное окно, в течение которого пользователи могут быть подвержены межсайтовым атакам.

Примечание. Это двухминутное окно не распространяется на файлы cookie, которые были явно установлены с помощью атрибута SameSite=Lax.

Пытаться приурочить атаку к этому короткому промежутку времени несколько непрактично. С другой стороны, если вы найдёте на сайте гаджет, позволяющий заставить жертву выдать новую сессионную cookie, вы сможете упреждающе обновить её cookie перед тем, как приступить к основной атаке. Например, выполнение входа в систему на основе OAuth может каждый раз приводить к новой сессии, поскольку служба OAuth не всегда знает, вошёл ли пользователь на целевой сайт.

Чтобы запустить обновление cookie-файлов без необходимости повторного входа в систему вручную, необходимо использовать навигацию верхнего уровня, которая обеспечивает включение cookie-файлов, связанных с текущей сессией OAuth. Это создаёт дополнительную проблему, поскольку в этом случае необходимо перенаправить пользователя обратно на свой сайт, чтобы осуществить CSRF-атаку.

В качестве альтернативы можно запустить обновление cookie из новой вкладки, чтобы браузер не покинул страницу до того, как вы сможете провести финальную атаку. Небольшая проблема с этим подходом заключается в том, что браузеры блокируют всплывающие вкладки, если они не открываются вручную. Например, следующее всплывающее окно будет заблокировано браузером по умолчанию:

window.open('https://vulnerable-website.com/login/sso');

Чтобы обойти эту проблему, можно обернуть оператор в обработчик события onclick следующим образом:

window.onclick = () => {
window.open('https://vulnerable-website.com/login/sso');
}

Таким образом, метод window.open() будет вызываться только тогда, когда пользователь кликнет где-либо на странице.

Дополнительные материалы

Предыдущая Статья

Освоение z-index в CSS

Следующая Статья

Понимание логических свойств CSS