Многим веб-приложениям необходимо отображать контент, управляемый пользователем. Это может быть как простая демонстрация загруженных пользователем изображений (например, фотографий профиля), так и сложная задача, например, рендеринг HTML-кода, управляемого пользователем (например, учебное пособие по веб-разработке). Обеспечить безопасность таких приложений всегда было непросто, поэтому мы работали над поиском простых, но надежных решений, применимых к большинству типов веб-приложений.
Классические решения для изоляции ненадежного контента
Классическое решение для безопасной доставки контента, контролируемого пользователем, — использование так называемых доменов-песочниц . Основная идея заключается в том, что если основной домен вашего приложения — example.com , вы можете доставлять весь ненадежный контент на exampleusercontent.com . Поскольку эти два домена являются межсайтовыми , любой вредоносный контент на exampleusercontent.com не сможет повлиять example.com . Этот подход можно использовать для безопасной доставки всех видов ненадежного контента, включая изображения, загрузки и HTML. Хотя может показаться, что это не обязательно для изображений или загрузок, это помогает избежать рисков, связанных с перехватом контента , особенно в устаревших браузерах. Домены-песочницы широко используются в отрасли и хорошо работают уже долгое время. Но у них есть два основных недостатка:
- Приложениям часто необходимо ограничивать доступ к контенту для одного пользователя, что требует реализации аутентификации и авторизации. Поскольку домены песочницы намеренно не используют общие файлы cookie с основным доменом приложения, обеспечить безопасность этого процесса очень сложно. Для поддержки аутентификации сайтам приходится либо полагаться на URL-адреса возможностей , либо устанавливать отдельные файлы cookie для аутентификации в домене песочницы. Второй метод особенно проблематичен в современном вебе, где многие браузеры по умолчанию ограничивают использование межсайтовых файлов cookie.
- Хотя пользовательский контент изолирован от основного сайта, он не изолирован от другого пользовательского контента. Это создает риск того, что вредоносный пользовательский контент может атаковать другие данные в изолированном домене (например, путем чтения данных из того же источника).
Также стоит отметить, что домены-песочницы помогают снизить риски фишинга, поскольку ресурсы четко сегментированы на изолированном домене.
Современные решения для предоставления пользовательского контента
Со временем интернет эволюционировал, и теперь существуют более простые и безопасные способы распространения ненадежного контента. Существует множество различных подходов, поэтому мы опишем два решения, которые мы используем в Google.
Подход 1: Предоставление контента неактивным пользователям.
Если сайту необходимо отображать только контент, недоступный неактивным пользователям (то есть контент, не являющийся HTML или JavaScript, например, изображения и файлы для скачивания), теперь это можно безопасно сделать без изолированного домена-песочницы. Для этого необходимы два ключевых шага:
- Всегда устанавливайте заголовок
Content-Typeна общеизвестный MIME-тип , поддерживаемый всеми браузерами и не содержащий активного контента. В случае сомнений, безопасным выбором будетapplication/octet-stream. - Кроме того, всегда устанавливайте заголовки ответа, чтобы браузер полностью изолировал ответ.
| Заголовок ответа | Цель |
|---|---|
X-Content-Type-Options: nosniff | Предотвращает перехват контента. |
Content-Disposition: attachment; filename="download" | Запускает загрузку, а не отрисовку. |
Content-Security-Policy: sandbox | Изолирует контент, как если бы он размещался на отдельном домене. |
Content-Security-Policy: default-src ‘none' | Отключает выполнение JavaScript (и включение любых подресурсов). |
Cross-Origin-Resource-Policy: same-site | Предотвращает включение страницы в межсайтовый контент. |
Такое сочетание заголовков гарантирует, что ответ может быть загружен вашим приложением только как подресурс или загружен пользователем как файл. Кроме того, заголовки обеспечивают многоуровневую защиту от ошибок браузера благодаря заголовку песочницы CSP и ограничению default-src . В целом, описанная настройка обеспечивает высокую степень уверенности в том, что ответы, предоставляемые таким образом, не могут привести к уязвимостям внедрения или изоляции.
эшелонированная оборона
Хотя предложенное решение в целом представляет собой достаточную защиту от XSS-атак, существует ряд дополнительных мер по усилению безопасности, которые можно применить для обеспечения более высокого уровня защиты:
- Установите заголовок
X-Content-Security-Policy: sandboxдля обеспечения совместимости с IE11. - Установите заголовок
Content-Security-Policy: frame-ancestors 'none', чтобы заблокировать встраивание конечной точки. - Пользовательский контент в изолированной поддомене в песочнице создан следующим образом:
- Предоставление пользовательского контента на изолированном поддомене (например, Google использует домены типа
product.usercontent.google.com). - Установите параметры
Cross-Origin-Opener-Policy: same-originиCross-Origin-Embedder-Policy: require-corp, чтобы включить изоляцию между источниками .
- Предоставление пользовательского контента на изолированном поддомене (например, Google использует домены типа
Подход 2: Предоставление активного пользовательского контента
Безопасная подача активного контента (например, изображений HTML или SVG) также может осуществляться без недостатков классического подхода с использованием изолированной среды.
Простейший вариант — использовать заголовок Content-Security-Policy: sandbox чтобы указать браузеру изолировать ответ. Хотя не все веб-браузеры реализуют изоляцию процессов для документов в песочнице, постоянное совершенствование моделей процессов браузеров, вероятно, улучшит разделение изолированного контента от встраиваемых приложений. Если атаки SpectreJS и компрометация рендерера выходят за рамки вашей модели угроз, то использование песочницы CSP, вероятно, будет достаточным решением. В Google мы разработали решение, которое может полностью изолировать ненадежный активный контент, модернизируя концепцию доменов песочницы. Основная идея заключается в следующем:
- Создайте новый тестовый домен, который будет добавлен в список общедоступных суффиксов ( PSL). Например, добавив
exampleusercontent.comв PSL, вы можете гарантировать, чтоfoo.exampleusercontent.comиbar.exampleusercontent.comбудут работать на разных сайтах и, следовательно, будут полностью изолированы друг от друга. - Все URL-адреса, соответствующие
*.exampleusercontent.com/shimперенаправляются на статический файл-заглушку. Этот файл содержит короткий фрагмент HTML и JavaScript, который прослушивает обработчик событийmessageи отображает любой полученный контент. - Для использования этой функции продукт создает либо iframe, либо диалоговое окно по адресу
$RANDOM_VALUE.exampleusercontent.com/shimи используетpostMessageдля отправки ненадежного контента в shim для рендеринга. - Отображаемое содержимое преобразуется в объект Blob и отображается внутри изолированного iframe .
По сравнению с классическим подходом к использованию изолированного домена, это гарантирует полную изоляцию всего контента на уникальном сайте. Кроме того, поскольку основное приложение самостоятельно обрабатывает получение данных для отображения, отпадает необходимость в использовании URL-адресов, определяющих возможности приложения.
Заключение
Вместе эти два решения позволяют перейти от классических тестовых доменов, таких как googleusercontent.com , к более безопасным решениям, совместимым с блокировкой файлов cookie сторонних разработчиков. В Google мы уже перевели множество продуктов на использование этих решений и планируем еще больше миграций в следующем году.