Как реализован механизм same origin policy в браузере на какие браузерные api он распространяется
В вычислениях политика одного и того же происхождения (иногда сокращенно SOP ) является важной концепцией в модели безопасности веб-приложений . В соответствии с политикой веб-браузер разрешает сценариям, содержащимся на первой веб-странице, получать доступ к данным на второй веб-странице, но только в том случае, если обе веб-страницы имеют одно и то же происхождение . Источник определяется как комбинация схемы URI , имени хоста и номера порта . Эта политика предотвращает получение вредоносным сценарием на одной странице доступа к конфиденциальным данным на другой веб-странице через объектную модель документа этой страницы .
Очень важно помнить, что политика одного и того же происхождения применяется только к скриптам. Это означает, что к таким ресурсам, как изображения, CSS и динамически загружаемые скрипты, можно получить доступ из разных источников через соответствующие теги HTML (заметным исключением являются шрифты). Атаки используют тот факт, что одна и та же политика происхождения не применяется к тегам HTML.
СОДЕРЖАНИЕ
История
Концепция политики одинакового происхождения была введена Netscape Navigator 2.02 в 1995 году, вскоре после появления JavaScript в Netscape 2.0. JavaScript позволяет создавать сценарии на веб-страницах и, в частности, программный доступ к объектной модели документа (DOM).
Изначально политика была разработана для защиты доступа к DOM, но с тех пор была расширена для защиты конфиденциальных частей глобального объекта JavaScript.
Реализация
Правила определения происхождения
Алгоритм, используемый для вычисления «происхождения» URI, указан в RFC 6454, раздел 4. Для абсолютных URI источником является тройка . Если URI не использует иерархический элемент в качестве центра присвоения имен (см. RFC 3986 , раздел 3.2) или если URI не является абсолютным URI, то используется глобальный уникальный идентификатор. Два ресурса считаются имеющими одно и то же происхождение тогда и только тогда, когда все эти значения абсолютно одинаковы.
В отличие от других браузеров, Internet Explorer не включает порт в расчет источника, используя вместо него Зону безопасности.
Доступ для чтения к конфиденциальным ответам из разных источников с помощью многоразовой аутентификации
Политика одного и того же происхождения защищает от повторного использования аутентифицированных сеансов в разных источниках. В следующем примере показана потенциальная угроза безопасности, которая может возникнуть без политики одного и того же происхождения. Предположим, что пользователь посещает веб-сайт банка и не выходит из системы. Затем пользователь переходит на другой сайт с вредоносным кодом JavaScript, который запрашивает данные с сайта банка. Поскольку пользователь по-прежнему авторизован на сайте банка, вредоносный код может делать все, что пользователь может сделать на сайте банка. Например, он может получить список последних транзакций пользователя, создать новую транзакцию и т. Д. Это связано с тем, что в исходном духе всемирной паутины браузеры должны помечать детали аутентификации, такие как файлы cookie сеанса и платформенные. виды уровня заголовка запроса авторизации к сайту банка в зависимости от домена сайта банка.
Владельцы сайтов банка ожидают, что обычные браузеры пользователей, посещающих вредоносный сайт, не позволят коду, загруженному с вредоносного сайта, получить доступ к cookie банковского сеанса или авторизации на уровне платформы. Хотя это правда, что JavaScript не имеет прямого доступа к куки-файлу банковской сессии, он все же может отправлять и получать запросы на банковский сайт с помощью куки-файла сеанса банковского сайта. Политика одинакового происхождения была введена как требование для браузеров, ориентированных на безопасность, чтобы запретить доступ для чтения к ответам из разных источников, с предположением, что большинство пользователей предпочитают использовать совместимые браузеры. Политика не запрещает пишет. Противодействие злоупотреблению разрешением на запись требует дополнительной защиты CSRF со стороны целевых сайтов.
Ослабление политики одинакового происхождения
В некоторых случаях политика одного и того же происхождения является слишком строгой, что создает проблемы для крупных веб-сайтов, использующих несколько поддоменов . Сначала для передачи данных между документами, находящимися в разных доменах , использовался ряд обходных приемов, таких как использование идентификатора фрагмента или window.name свойства. Современные браузеры поддерживают несколько методов контролируемого ослабления политики одного и того же происхождения:
Заражение данных
Netscape Navigator кратко содержал функцию проверки заражения . Эта функция была экспериментально представлена в 1997 году как часть Netscape 3. По умолчанию эта функция была отключена, но, если она была включена пользователем, она позволяла веб-сайтам пытаться читать свойства JavaScript окон и фреймов, принадлежащих другому домену. Затем браузер спросит пользователя, разрешить ли рассматриваемый доступ.
document.domain свойство
Эта document.domain концепция была представлена как часть Netscape Navigator 3, выпущенного в 1996 году.
Совместное использование ресурсов между источниками
JSONP
Поскольку HTML- <script> элементам разрешено извлекать и выполнять контент из других доменов, страница может обходить политику того же происхождения и получать данные JSON из другого домена, загружая ресурс, который возвращает полезную нагрузку JSONP. Полезные данные JSONP состоят из внутренних полезных данных JSON, обернутых предварительно определенным вызовом функции. Когда ресурс скрипта загружается браузером, будет вызвана назначенная функция обратного вызова для обработки обернутой полезной нагрузки JSON.
WebSockets
Современные браузеры разрешают сценарию подключаться к адресу WebSocket без применения политики того же происхождения. Однако они распознают использование URI WebSocket и вставляют заголовок Origin: в запрос, который указывает источник сценария, запрашивающего соединение. Для обеспечения межсайтовой безопасности сервер WebSocket должен сравнить данные заголовка с белым списком источников, которым разрешено получать ответ.
Угловые шкафы
Поведение проверок одного и того же происхождения и связанных механизмов недостаточно четко определено в ряде крайних случаев, например, для псевдопротоколов, у которых нет четко определенного имени хоста или порта, связанного с их URL-адресами ( file:, data: и т. Д. .). Исторически это вызывало изрядное количество проблем с безопасностью, таких как обычно нежелательная способность любого локально хранимого файла HTML получать доступ ко всем другим файлам на диске или связываться с любым сайтом в Интернете.
Наконец, определенные типы атак, такие как повторное связывание DNS или прокси на стороне сервера, позволяют частично нарушить проверку имени хоста и позволяют мошенническим веб-страницам напрямую взаимодействовать с сайтами через адреса, отличные от их «истинных», канонических источник. Воздействие таких атак ограничено очень конкретными сценариями, поскольку браузер по-прежнему считает, что он взаимодействует с сайтом злоумышленника, и поэтому не раскрывает сторонние файлы cookie или другую конфиденциальную информацию злоумышленнику.
Политика одинакового источника (same-origin policy) определяет как документ или скрипт, загруженный из одного источника (origin), может взаимодействовать с ресурсом из другого источника. Это помогает изолировать потенциально вредоносные документы, снижая количество возможных векторов атак.
Определение origin
Две страницы имеют одинаковый origin (источник) если протокол , порт (если указан), и хост одинаковы для обоих страниц. Время от времени, вы можете видеть это как "scheme/host/port tuple" (где "tuple" переводится как кортеж или запись набор из трёх компонент, которые вместе составляют единое целое).
Наследование origins
Контент из about:blank и javascript: адреса наследуют источник документа, содержащего этот URL, поскольку они не содержат информации о сервере происхождения.
Например, about:blank часто используется в качестве URL новых, пустых окон в которые родительский скрипт записывает контент (например, с помощью Window.open() (en-US) ). Если это окно также содержит JavaScript, то скрипт будет наследовать то же происхождение, что и его родитель.
data: адреса получают новый, пустой, безопасный контекст.
Исключения в Internet Explorer
Internet Explorer два основных исключения из политики одно происхождения:
Эти исключения являются нестандартными и не поддерживаются в любом другом браузере
Изменение origin
Номер порта проверяется браузером отдельно. Любой вызов document.domain , включающий document.domain = document.domain , заменяет номер порта, устанавливая его в значение null . Следовательно, невозможно вызов company.com:8080 обозначить company.com одной лишь установкой document.domain = "company.com" в начале. Он должен быть установлен в обоих случаях и номер портов в этих случаях должны равняться значению null .
Замечание: Когда используется document.domain для разрешения поддомена для родительского доступа к нему, вы должны установить document.domain в такое же значение, как в родительском домене, так и в поддомене. Это необходимо, даже если при этом просто восстанавливается исходное значение родительского домена. Несоблюдение этого правила может привести к ошибкам разрешений.
Cross-origin network access
Here are some examples of resources which may be embedded cross-origin:
- JavaScript with <script src="https://developer.mozilla.org/ru/docs/Web/Security/"></script> . Error messages for syntax errors are only available for same-origin scripts.
- CSS with <link rel="stylesheet" href=". "> . Due to the relaxed syntax rules of CSS, cross-origin CSS requires a correct Content-Type header. Restrictions vary by browser: IE, Firefox, Chrome, Safari (scroll down to CVE-2010-0051) and Opera.
- Images with <img> . Supported image formats include PNG, JPEG, GIF, BMP, SVG, .
- Media files with <video> and <audio> .
- Plug-ins with <object> , <embed> and <applet> .
- Fonts with @font-face . Some browsers allow cross-origin fonts, others require same-origin fonts.
- Anything with <frame> and <iframe> . A site can use the X-Frame-Options header to prevent this form of cross-origin interaction.
How to allow cross-origin access
Use CORS to allow cross-origin access.
How to block cross-origin access
- To prevent cross-origin writes, check for an unguessable token in the request, known as a Cross-Site Request Forgery (CSRF) token. You must prevent cross-origin reads of pages that know this token.
- To prevent cross-origin reads of a resource, ensure that it is not embeddable. It is often necessary to prevent embedding because embedding a resource always leaks some information about it.
- To prevent cross-origin embedding, ensure that your resource cannot be interpreted as one of the embeddable formats listed above. The browser does not respect the Content-Type in most cases. For example, if you point a <script> tag at an HTML document, the browser will try to parse the HTML as JavaScript. When your resource is not an entry point to your site, you can also use a CSRF token to prevent embedding.
Cross-origin script API access
JavaScript APIs such as iframe.contentWindow , window.parent , window.open (en-US) and window.opener (en-US) allow documents to directly reference each other. When the two documents do not have the same origin, these references provide very limited access to Window and Location objects, as described in the next two sections.
To communicate further between documents from different origins, use window.postMessage .
Window
The following cross-origin access to Window properties is allowed:
Methods |
---|
window.blur |
window.close |
window.focus (en-US) |
window.postMessage |
Attributes | |
---|---|
window.closed | Read only. |
window.frames | Read only. |
window.length | Read only. |
window.location | Read/write. |
window.opener (en-US) | Read only. |
window.parent | Read only. |
window.self | Read only. |
window.top | Read only. |
window.window (en-US) | Read only. |
Some browsers allow access to more properties than the specification allows.
Location
The following cross-origin access to Location properties is allowed:
Methods |
---|
location.replace |
Attributes | |
---|---|
URLUtils.href | Write only. |
Some browsers allow access to more properties than the specification allows.
Cross-origin data storage access
Access to data stored in the browser such as localStorage and IndexedDB are separated by origin. Each origin gets its own separate storage, and JavaScript in one origin cannot read from or write to the storage belonging to another origin.
Каждый разработчик периодически сталкивается с огромной красной строкой в консоли — Access to fetched has been blocked by CORS policy . Да, это здорово расстраивает. И хотя есть способы быстро избавиться от этой ошибки, давайте сегодня не будем принимать их как должное — лучше разберёмся, что на самом деле делает CORS и почему эта технология на самом деле наш друг.
Что произошло? Мы отправили такой же запрос, но на этот раз браузер выдал странную ошибку. Мы только что увидели CORS в действии. Давайте разберёмся, почему возникла эта ошибка, и что она означает.
Правило одинакового источника (Same-Origin Policy)
Ресурс считается принадлежащим к другому источнику (cross-origin), если он располагается на другом домене/поддомене, протоколе или порте.
Это, конечно, здорово, но для чего правило одинакового источника вообще существует?
Представим, что это правило не работает, а вы случайно нажали на какую-то вирусную ссылку, которую прислала ваша тётушка на Фейсбуке. Ссылка перенаправляет вас на мошеннический сайт, который с помощью фрейма загружает интерфейс сайта вашего банка и успешно залогинивает вас с помощью сохранённых куки.
Разработчики этого мошеннического сайта сделали так, чтобы он имел доступ к фрейму и мог взаимодействовать с DOM сайта вашего банка — так они смогут переводить деньги на свой счёт от вашего имени.
Да, это огромная угроза безопасности — мы ведь не хотим, чтобы кто угодно имел доступ к чему угодно.
К счастью, здесь приходит на помощь правило одинакового источника: оно гарантирует, что мы можем получить доступ только к ресурсам из того же самого источника.
Но какое отношение всё это имеет к CORS?
CORS на стороне клиента
Несмотря на то, что правило одинакового источника применяется исключительно к скриптам, браузеры распространили его и на JavaScript-запросы: по умолчанию можно получить доступ к ресурсам только из одинакового источника.
Но нам ведь часто нужно обращаться к ресурсам из других источников… Может, тогда фронтенду стоит взаимодействовать с API на бэкенде, чтобы загружать данные? Чтобы обеспечить безопасность запросов к другим источникам, браузеры используют механизм под названием CORS.
Аббревиатура CORS расшифровывается как Cross-Origin Resource Sharing (Технология совместного использования ресурсов между разными источниками). Несмотря на то, что браузеры не позволяют получать доступ к ресурсам из разных источников, можно использовать CORS, чтобы внести небольшие коррективы в эти ограничения и при этом быть уверенным, что доступ будет безопасным.
Чтобы браузер разрешил доступ к ресурсам из другого источника, он должен получить определённые заголовки в ответе от сервера, которые указывают, разрешает ли сервер запросы из других источников.
CORS на стороне сервера
Существует несколько CORS-заголовков, но браузеру нужен всего один из них, чтобы разрешить доступ к ресурсам из разных источников — Access-Control-Allow-Origin . Его значение определяет, из каких источников можно получить доступ к ресурсам на сервере.
Отлично, теперь мы можем получать ресурсы из другого источника. А что будет, если мы попытаемся получить к ним доступ из источника, который не указан в заголовке Access-Control-Allow-Origin ?
Да, теперь CORS выдаёт эту печально известную ошибку, которая иногда всех нас так расстраивает. Но сейчас нам понятно, какой смысл она несет.
В качестве значения разрешённых источников CORS позволяет указать спецсимвол * . Он означает, что доступ к ресурсам открыт из всех источников, поэтому используйте его с осторожностью.
Кроме Access-Control-Allow-Origin , мы можем использовать и многие другие CORS-заголовки. Бэкенд-разработчик может изменить правила CORS на сервере так, чтобы разрешать/блокировать определённые запросы.
Ещё один довольно распространённый заголовок — Access-Control-Allow-Methods . С ним будут разрешены только те запросы из других источников, которые выполнены с применением перечисленных методов.
В данном случае разрешены только запросы с методами GET , POST , или PUT . Запросы с другими методами (например, PATCH или DELETE ) будут блокироваться.
Если вам интересно почитать о других CORS-заголовках, ознакомьтесь с их списком на MDN.
С PUT , PATCH и DELETE CORS работает с по-другому. В этих “непростых” случаях используются так называемые предварительные запросы (preflight requests).
Предварительные запросы
Существует два типа CORS-запросов: простые и предварительные. Тип запроса зависит от хранящихся в нём значений (не волнуйтесь, здесь не надо будет ничего запоминать).
Запрос считается простым, если в нём используются методы GET и POST и нет никаких пользовательских заголовков. Любые другие запросы (например, с методами PUT , PATCH или DELETE ) — предварительные.
Если интересно узнать, каким требованиям должен соответствовать запрос, чтобы называться простым, почитайте эту статью на MDN.
Но что означают и почему существуют “предварительные запросы”?
Если всё в порядке, браузер посылает текущий запрос на сервер, а тот в ответ присылает данные, которые мы запрашивали.
Если же возникает проблема, CORS блокирует предварительный запрос, а текущий вообще уже не будет отправлен. Предварительный запрос — отличный способ уберечь нас от получения доступа или изменения ресурсов на серверах, у которых (пока что) не настроены правила CORS. Сервера защищены от потенциально нежелательных запросов из других источников.
Чтобы уменьшить число обращений к серверу, можно кэшировать предварительные ответы, добавив к CORS-запросам заголовок Access-Control-Max-Age . Так браузеру не придётся каждый раз отправлять новый предварительный запрос.
Учётные данные
Куки, заголовки авторизации, TLS-сертификаты по умолчанию включены только в запросы из одинакового источника. Однако нам может понадобиться использовать учётные данные и в запросах из разных источников. Возможно, мы захотим включить куки в запрос, который сервер сможет использовать для идентификации пользователя.
В CORS по умолчанию отсутствуют учётные данные, но это можно изменить, добавив CORS-заголовок Access-Control-Allow-Credentials .
Если необходимо включить куки и другие заголовки авторизации в запрос из другого источника, нужно установить значение true в поле withCredentials запроса, а также добавить в ответ заголовок Access-Control-Allow-Credentials .
Готово — теперь мы можем включать учётные данные в запрос из другого источника.
Думаю, мы все согласимся с тем, что появление ошибок CORS порой расстраивает, но, тем не менее, здорово, что CORS позволяет безопасно отправлять запросы из разных источников в браузере — считаю, что мы должны любить эту технологию чуточку сильнее :)
Разумеется, о правиле одинакового источника и CORS можно рассказать гораздо больше, но я просто не смогу уместить всё это в одной статье. К счастью, ресурсов много (к примеру, спецификация W3) — вам будет к чему обратиться, если захотите подробнее изучить эту тему.
Эта статья рассказывает что означает эта ошибка и как от нее избавиться.
Пусть там будет примерно такая функция получения GET запроса:
Пусть там будет простая функция входа в систему, где пользователи вводят общее секретное слово secret и им затем ему устанавливается cookie, идентифицируя их как аутентифицированных:
И пусть у нас будет некое приватное API для каких нибудь личных данных в /private, только для аутентифицированных пользователей.
Запрос нашего API через AJAX из других доменов
И это не будет работать!
Сам по себе запрос был успешным, но результат оказался не доступен. Описание причины можно найти в консоли JavaScript:
Ага! Нам не хватает заголовка Access-Control-Allow-Origin. Но зачем он нам и для чего он вообще нужен?
Same-Origin Policy
Причиной, по которой мы не получим ответ в JavaScript, является Same-Origin Policy. Эта ограничительная мера была придумана разработчиками браузеров что бы веб-сайт не мог получить ответ на сгенерированный AJAX запрос к другому веб-сайту находящемуся по другому адресу .
Same-Origin Policy предотвращает именно это.
«источник (origin)» в этом случае состоит из
Пару слов о CSRF
При CSRF-атаке злоумышленник отправляет запрос сторонней странице в фоновом режиме, например, отправляя POST запрос на веб-сайт вашего банка. Если у вас в этот момент есть действительный сеанс с вашим банком, любой веб-сайт может сгенерировать запрос в фоновом режиме, который будет выполнен, если ваш банк не использует контрмеры против CSRF.
Например, API, которое позволяет отправлять электронные письма, выполняя POST запрос, отправит электронное письмо, если мы предоставим ему правильные данные. Злоумышленнику не нужно заботится о результате, его забота это отправляемое электронное письмо, которое он получит независимо от возможности видеть ответ от API.
Включение CORS для нашего публичного API
Допустим нам нужно разрешить работу JavaScript на сторонних сайтах (например, 127.0.0.1:8000) что бы получать доступ к нашим ответам API. Для этого нам нужно включить CORS в заголовок ответа от сервера. Это делается на стороне сервера:
Здесь мы устанавливаем заголовку Access-Control-Allow-Origin значение *, что означает: что любому хосту разрешен доступ к этому URL и ответу в браузере:
Непростые запросы и предварительные запросы (preflights)
- Запросы: GET,POST
- Тип содержимого следующего:
- text/plain
- application/x-www-form-urlencoded
- multipart/form-data
Допустим теперь 127.0.0.1:8000 немного меняет реализацию, и теперь он обрабатывает запросы в формате JSON:
Но это снова все ломает!
На этот раз консоль показывает другую ошибку:
Любой заголовок, который не разрешен для простых запросов, требует предварительного запроса (preflight request).
Этот механизм позволяет веб-серверам решать, хотят ли они разрешить фактический запрос. Браузер устанавливает заголовки Access-Control-Request-Headers и Access-Control-Request-Method, чтобы сообщить серверу, какой запрос ожидать, и сервер должен ответить соответствующими заголовками.
Но наш сервер еще не отвечает с этими заголовками, поэтому нам нужно добавить их:
Теперь мы снова может получить доступ к ответу.
Credentials и CORS
Теперь давайте предположим, что нам нужно залогинится на 127.0.0.1:3000 что бы получить доступ к /private с конфиденциальной информацией.
При всех наших настройках CORS может ли другой сайт так же получить эту конфиденциальную информацию?
Мы пропустили код реализации входа в на сервер так как он не обязателен для объяснения материала.
Независимо от того, попытаемся ли мы залогинится на 127.0.0.1:3000 или нет, мы увидим «Please login first».
Но опять это не будет работать в браузере. И это хорошая новость, на самом деле.
Итак, мы не хотим, чтобы злоумышленник имел доступ к приватным данным, но что, если мы хотим, чтобы 127.0.0.1:8000 имел доступ к /private?
В этом случае нам нужно установить для заголовка Access-Control-Allow-Credentials значение true:Браузер не позволит нам так легко совершить ошибку.
Если мы хотим разрешить 127.0.0.1:8000 доступ к /private, нам нужно указать точный источник в заголовке:
Разрешить множественные источники (origin)
Теперь мы разрешили одному источнику делать запросы к другому источнику с данными аутентификации. Но что, если у нас есть несколько других источников?
В этом случае мы, вероятно, хотим использовать белый список:
Опять же: не отправляйте напрямую req.headers.origin в качестве разрешенного заголовка CORS. Это позволит любому веб-сайту получить доступ к приватным данным.
Из этого правила могут быть исключения, но, по крайней мере, дважды подумайте, прежде чем внедрять CORS с учетными данными без белого списка.Заключение
В этой статье мы рассмотрели Same-Origin Policy и то, как мы можем использовать CORS, чтобы разрешать запросы между источниками, когда это необходимо.
Это требует настройки на стороне сервера и на стороне клиента и в зависимости от запроса вызовет предварительный (preflight) запрос.
При работе с аутентифицированными запросами перекрестного происхождения следует проявлять дополнительную осторожность. Белый список может помочь разрешить нескольким источникам без риска утечки конфиденциальных данных (которые защищены аутентификацией).
Читайте также: