Правило ограничения домена

Правило ограничения домена (англ. Same-origin policy, SOP) — концепция в модели безопасности веб-приложений, направленная на предотвращение нежелательного доступа к данным между документами, загруженными из разных источников. Согласно этому правилу, веб-браузер разрешает сценариям (скриптам), находящимся на одной веб-странице, доступ к данным на другой только в том случае, если обе страницы имеют одинаковое происхождение (origin). Под происхождением понимается комбинация схемы URI, имени хоста и номера порта. Такая политика предотвращает возможность получения доступа к конфиденциальным данным вредоносными скриптами через объектную модель документа (DOM) других страниц[1].

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

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

Существуют механизмы для ослабления строгого ограничения SOP, главное из которых — обмен ресурсами между источниками (CORS).

История

Концепция правила ограничения домена появилась во Netscape Navigator 2.02 в 1995 году[1], вскоре после появления JavaScript во Netscape Navigator 2.0[2].[3] JavaScript позволил использовать языки сценариев на веб-страницах и, в частности, программный доступ к DOM.

Изначально политика была разработана для защиты доступа к DOM, но затем была распространена и на другие чувствительные части глобального объекта JavaScript.

Реализация

Все современные браузеры реализуют различные варианты правила ограничения домена как важную часть системы безопасности[4]. Политики не обязаны полностью соответствовать единому стандарту[5], но часто расширяются для других веб-технологий, таких как Microsoft Silverlight, Adobe Flash, Adobe Acrobat, либо для механизмов, отличных от прямого доступа к DOM, например XMLHttpRequest.

Правила определения происхождения

Алгоритм для вычисления «происхождения» URI описан в RFC 6454, раздел 4. Для абсолютных URI происхождение определяется как тройка {схема, хост, порт}. Если URI не использует иерархический элемент в качестве имени авторитета (см. RFC 3986, раздел 3.2) или если URI не является абсолютным, используется глобальный уникальный идентификатор. Два ресурса считаются принадлежащими одному происхождению только если все эти значения совпадают.

Для примера ниже приведена таблица, иллюстрирующая результаты проверки различных URL относительно «http://www.example.com/dir/page.html»:

Сравниваемый URL Результат Причина
http://www.example.com/dir/page2.html Да Та же схема, хост и порт
http://www.example.com/dir2/other.html Да Та же схема, хост и порт
http://username:password@www.example.com/dir2/other.html Да Та же схема, хост и порт
http://www.example.com:80/dir/other.html Да Современные браузеры по умолчанию подставляют стандартный порт протокола при его отсутствии[6].[7]
http://www.example.com:81/dir/other.html Нет Та же схема и хост, но другой порт
https://www.example.com/dir/other.html Нет Другая схема
http://en.example.com/dir/other.html Нет Другой хост
http://example.com/dir/other.html Нет Другой хост (требуется полное совпадение)
http://v2.www.example.com/dir/other.html Нет Другой хост (требуется полное совпадение)
data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAA= Нет Другая схема

В отличие от других браузеров, Internet Explorer не включает порт в расчёт происхождения, а использует вместо него определённую зону безопасности[8].

Доступ для чтения к чувствительным кросс-доменным ответам через повторное использование аутентификации

Правило ограничения домена защищает от повторного использования аутентифицированных сессий между источниками. Пример потенциального риска: пользователь заходит на банковский сайт и не выходит из аккаунта, после чего посещает другой сайт с вредоносным JavaScript-кодом, который делает запросы к банковскому сайту. Поскольку пользователь авторизован, вредоносный код может выполнять любые действия от лица пользователя. Особенность работы веб-браузеров заключается в том, что они обязаны отправлять аутентификационные данные (например, сессионные cookie или заголовок Authorization) на сайт по домену.

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

Ослабление правила ограничения домена

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

Отметка данных (taint checking)

В браузере Netscape Navigator в 1997—1998 годах экспериментально существовала функция отметки данных (taint checking), позволявшая при активации пытаться получить доступ к свойствам JavaScript окон и кадров других доменов, при этом браузер спрашивал пользователя о разрешении[9].[10][11]

Свойство document.domain

Если два окна (или кадра) устанавливают свойство document.domain в одно и то же значение, правило ограничения домена ослабляется для этих окон, и они могут взаимодействовать напрямую. Например, скрипты с orders.example.com и catalog.example.com могут установить document.domain в «example.com», и тогда каждый может читать свойства другого. Установка этого свойства приводит к тому, что порт implicitly становится null, а большинство браузеров интерпретирует его иначе, чем порт 80 или неуказанный порт. Для корректного взаимодействия следует явно выставлять document.domain в обоих документах[12].

Свойство document.domain было добавлено в Netscape Navigator 3 в 1996 году[13].[9]

Обмен ресурсами между источниками (CORS)

Другой стандартный способ ослабления правила — CORS. В рамках этого стандарта к HTTP-запросам добавляется новый заголовок Origin, а сервер может назначить заголовок Access-Control-Allow-Origin, ограничивающий список разрешённых источников или разрешающий доступ с любых сайтов. Браузеры Firefox 3.5, Safari 4 и Internet Explorer 10 используют этот подход для разрешения кросс-доменных запросов через XMLHttpRequest, которые в иных условиях были бы запрещены.

Межстраничная передача сообщений

Ещё одна техника — межстраничная передача сообщений (cross-document messaging), позволяющая скриптам одной страницы отправлять текстовые сообщения на другую страницу независимо от происхождения. Вызов метода postMessage() объекта Window асинхронно генерирует событие «onmessage» в целевом окне, где могут сработать заранее определённые обработчики. При этом скрипты не получают прямого доступа к чужим методам или переменным, но могут безопасно обмениваться сообщениями.

JSONP

Поскольку элементы HTML <script> разрешают получение и выполнение кода с других доменов, страница может обойти правило ограничения домена и получать JSON-данные из другого источника, загружая ресурс, возвращающий специальную JSONP-обёртку. Такая обёртка — это внутренний JSON, «завёрнутый» в вызов заранее определённой функции. После загрузки скрипта соответствующая функция-обработчик получает доступ к данным.

WebSocket

Современные браузеры разрешают скриптам устанавливать соединение с адресами WebSocket без применения правила ограничения домена, однако каждый запрос содержит заголовок Origin:, указывающий происхождение скрипта. Сервер WebSocket должен сверять значение этого заголовка, чтобы обеспечить безопасность кросс-доменных соединений.

Пограничные случаи

Поведение браузеров по правилам проверки происхождения неоднозначно в ряде пограничных случаев — например, для псевдо-протоколов без однозначно заданных имени хоста и порта (file:, data: и др.). Это стало источником ряда уязвимостей, таких как возможность локальных HTML-файлов получать доступ ко всем другим файлам на диске или взаимодействовать с любыми интернет-сайтами.

Кроме того, некоторые атаки — DNS-ребайдинг или проксирование на серверной стороне — могут частично обойти проверку хоста и позволить злоумышленникам обращаться к сайтам по альтернативным адресам. Однако такие атаки ограничены, поскольку браузер всё равно считает себя находящимся на сайте злоумышленника и не раскрывает сторонние cookie или другую критически важную информацию.

Атаки

Чтение информации

Даже при наличии правила ограничения домена (без ослабления через CORS) возможны определённые кросс-доменные атаки. Например, используя WebRTC, можно определить внутренний IP-адрес пользователя[14]. При попытке соединения с портом другого происхождения читать ответы нельзя, но скрипт может выяснить, открыт ли порт, по наступлению onload/onerror или по таймауту — что создаёт возможности для кросс-доменных сканирований портов.

JavaScript-фрагменты также используют техники утечки через кросс-доменные каналы[15] для добывания информации о сторонних сайтах. Противодействовать этим атакам можно при помощи политики Cross-Origin Resource Policy (CORP), позволяющей сайту блокировать сторонние ресурсы (например, изображения, видео, таблицы стилей), а также JavaScript-запросы fetch с параметром no-cors[16].[17]

Запись информации (CSRF)

Правило ограничения домена не препятствует браузеру выполнять запросы GET, POST, OPTIONS и TRACE — оно только не позволяет читать их ответы из кода пользователя. Поэтому если сервис уязвим к записи данных этими методами, он может быть атакован злоумышленниками.

Отдельно стоит отметить, что правило не применяется к cookie по историческим причинам[18]. Если несколько сайтов работают на одном имени хоста, но разных портах, все cookies будут доступны с любого из них (в отличие от самого правила ограничения домена). Это позволяет красть сессионные токены пользователей. Поэтому сервисы предпочитают использовать разные поддомены вместо портов.

Литература

Примечания