Ограничение «Same Origin» («тот же источник») ограничивает доступ окон и фреймов друг к другу, а также влияет на AJAX-запросы к серверу.
Причина, по которой оно существует – безопасность. Если есть два окна, в одном из которых vasya-pupkin.com
, а в другом gmail.com
, то мы бы не хотели, чтобы скрипт из первого мог читать нашу почту.
Сама концепция проста, но есть много важных исключений и особенностей, которые нужно знать для полного понимания этого правила.
Концепция Same Origin
Два URL считаются имеющим один источник («same origin»), если у них одинаковый протокол, домен и порт.
Эти URL имеют один источник:
http://site.com
http://site.com
/http://site.com/my/page.html
А вот эти – все из других источников:
- http://www.site.com (другой домен)
- http://site.org (другой домен)
- https://site.com (другой протокол)
- http://site.com:8080 (другой порт)
Существует ряд исключений, позволяющих-таки окнам с разных доменов обмениваться информацией, но прямой вызов методов друг друга и чтение свойств запрещены.
В действии
Если одно окно попытается обратиться к другому, то браузер проверит, из одного ли они источника. Если нет – доступ будет запрещён.
Например:
<iframe src="https://example.com"></iframe>
<script>
var iframe = document.body.children[0];
iframe.onload = function() {
try {
alert( iframe.contentWindow.document );
} catch (e) {
alert( "Ошибка: " + e.message );
}
}
</script>
Пример выше выведет ошибку.
Исключение: запись в location
Окна могут менять location
друг друга, даже если они из разных источников.
Причём читать свойства location
нельзя, одно окно не имеет право знать, на каком URL пользователь в другом. А вот запись браузеры считают безопасной.
Например, открыв на javascript.ru
iframe с http://example.com
, из этого ифрейма нельзя будет прочитать URL, а вот поменять его – запросто:
<iframe src="https://example.com"></iframe>
<script>
var iframe = document.body.children[0];
iframe.onload = function() {
try {
// не сработает (чтение)
alert( iframe.contentWindow.location.href );
} catch (e) {
alert( "Ошибка при чтении: " + e.message );
}
// сработает (запись)
iframe.contentWindow.location.href = 'https://wikipedia.org';
iframe.onload = null;
}
</script>
Если запустить код выше, то окно сначала загрузит example.com
, а потом будет перенаправлено на wikipedia.org
.
Исключение: поддомен 3-го уровня
Ещё одно важное исключение касается доменов третьего уровня.
Если несколько окон имеют общий домен второго уровня, к примеру john.site.com
, peter.site.com
, site.com
, и присваивают в document.domain
свой общий поддомен 2-го уровня site.com
, то все ограничения снимаются.
То есть, на всех этих сайтах должен быть код:
document.domain = 'site.com';
Тогда между ними не будет кросс-доменных ограничений.
Обратим внимание: свойство document.domain
должно быть присвоено на всех окнах, участвующих в коммуникации. Выглядит абсурдно, но даже на документе с site.com
нужно вызвать: document.domain="site.com"
. Иначе не будет работать.
Таким образом разные подсайты в рамках одного общего проекта могут взаимодействовать без ограничений.
Исключения в IE
В браузере Internet Explorer есть два своих, дополнительных исключения из Same Origin Policy.
-
Порт не входит в понятие «источник» (origin).
Это означает, что окно с
http://site.com
может свободно общаться сhttp://site.com:8080
.Это иногда используют для общения серверов, использующих один IP-адрес. Но допустимо такое только в IE.
-
Если сайт находится в зоне «Надёжные узлы», то в Internet Explorer ограничения к нему не применяются.
При этом подразумевается, что для этой зоны в параметрах «Безопасность» включена опция «Доступ к источникам данных за пределами домена».
Итого
Ограничение «одного источника» запрещает окнам и фреймам с разных источников вызывать методы друг друга и читать данные друг из друга.
При этом «из одного источника» означает «совпадают протокол, домен и порт».
У этого подхода ряд существенных исключений:
- Свойства
window.location.*
нельзя читать, но можно менять. - Домены третьего уровня с общим наддоменом могут поменять
document.domain
на их общий домен второго уровня, и тогда они смогут взаимодействовать без ограничений. - IE не включает порт в понятие источника. Кроме того, он позволяет снять ограничения для конкретного сайта включением в доверенную зону.