Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
126 lines (79 sloc) 7.18 KB

Кросс-доменные ограничения и их обход

Ограничение "Same Origin" ("тот же источник") ограничивает доступ окон и фреймов друг к другу, а также влияет на AJAX-запросы к серверу.

Причина, по которой оно существует -- безопасность. Если есть два окна, в одном из которых vasya-pupkin.com, а в другом gmail.com, то мы бы не хотели, чтобы скрипт из первого мог читать нашу почту.

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

Концепция Same Origin [#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.

  1. Порт не входит в понятие "источник" (origin).

    Это означает, что окно с http://site.com может свободно общаться с http://site.com:8080.

    Это иногда используют для общения серверов, использующих один IP-адрес. Но допустимо такое только в IE.

  2. Если сайт находится в зоне "Надёжные узлы", то в Internet Explorer ограничения к нему не применяются.

    При этом подразумевается, что для этой зоны в параметрах "Безопасность" включена опция "Доступ к источникам данных за пределами домена".

Итого

Ограничение "одного источника" запрещает окнам и фреймам с разных источников вызывать методы друг друга и читать данные друг из друга.

При этом "из одного источника" означает "совпадают протокол, домен и порт".

У этого подхода ряд существенных исключений:

  • Свойства window.location.* нельзя читать, но можно менять.
  • Домены третьего уровня с общим наддоменом могут поменять document.domain на их общий домен второго уровня, и тогда они смогут взаимодействовать без ограничений.
  • IE не включает порт в понятие источника. Кроме того, он позволяет снять ограничения для конкретного сайта включением в доверенную зону.