Get frames with javascript

Cross-window communication

The “Same Origin” (same site) policy limits access of windows and frames to each other.

The idea is that if a user has two pages open: one from john-smith.com , and another one is gmail.com , then they wouldn’t want a script from john-smith.com to read our mail from gmail.com . So, the purpose of the “Same Origin” policy is to protect users from information theft.

Same Origin

Two URLs are said to have the “same origin” if they have the same protocol, domain and port.

These URLs all share the same origin:

  • http://www.site.com (another domain: www. matters)
  • http://site.org (another domain: .org matters)
  • https://site.com (another protocol: https )
  • http://site.com:8080 (another port: 8080 )

The “Same Origin” policy states that:

  • if we have a reference to another window, e.g. a popup created by window.open or a window inside , and that window comes from the same origin, then we have full access to that window.
  • otherwise, if it comes from another origin, then we can’t access the content of that window: variables, document, anything. The only exception is location : we can change it (thus redirecting the user). But we cannot read location (so we can’t see where the user is now, no information leak).

In action: iframe

An tag hosts a separate embedded window, with its own separate document and window objects.

We can access them using properties:

  • iframe.contentWindow to get the window inside the .
  • iframe.contentDocument to get the document inside the , shorthand for iframe.contentWindow.document .

When we access something inside the embedded window, the browser checks if the iframe has the same origin. If that’s not so then the access is denied (writing to location is an exception, it’s still permitted).

For instance, let’s try reading and writing to from another origin:

 catch(e) < alert(e); // Security Error (another origin) >// also we can't READ the URL of the page in iframe try < // Can't read URL from the Location object let href = iframe.contentWindow.location.href; // ERROR >catch(e) < alert(e); // Security Error >// . we can WRITE into location (and thus load something else into the iframe)! iframe.contentWindow.location = '/'; // OK iframe.onload = null; // clear the handler, not to run it after the location change >; 

The code above shows errors for any operations except:

  • Getting the reference to the inner window iframe.contentWindow – that’s allowed.
  • Writing to location .
Читайте также:  Обработки ошибок php код

Contrary to that, if the has the same origin, we can do anything with it:

 ; 

The iframe.onload event (on the tag) is essentially the same as iframe.contentWindow.onload (on the embedded window object). It triggers when the embedded window fully loads with all resources.

…But we can’t access iframe.contentWindow.onload for an iframe from another origin, so using iframe.onload .

Windows on subdomains: document.domain

By definition, two URLs with different domains have different origins.

But if windows share the same second-level domain, for instance john.site.com , peter.site.com and site.com (so that their common second-level domain is site.com ), we can make the browser ignore that difference, so that they can be treated as coming from the “same origin” for the purposes of cross-window communication.

To make it work, each such window should run the code:

That’s all. Now they can interact without limitations. Again, that’s only possible for pages with the same second-level domain.

The document.domain property is in the process of being removed from the specification. The cross-window messaging (explained soon below) is the suggested replacement.

That said, as of now all browsers support it. And the support will be kept for the future, not to break old code that relies on document.domain .

Iframe: wrong document pitfall

When an iframe comes from the same origin, and we may access its document , there’s a pitfall. It’s not related to cross-origin things, but important to know.

Upon its creation an iframe immediately has a document. But that document is different from the one that loads into it!

So if we do something with the document immediately, that will probably be lost.

; 

We shouldn’t work with the document of a not-yet-loaded iframe, because that’s the wrong document. If we set any event handlers on it, they will be ignored.

How to detect the moment when the document is there?

The right document is definitely at place when iframe.onload triggers. But it only triggers when the whole iframe with all resources is loaded.

We can try to catch the moment earlier using checks in setInterval :

 < let newDoc = iframe.contentDocument; if (newDoc == oldDoc) return; alert("New document is here!"); clearInterval(timer); // cancel setInterval, don't need it any more >, 100); 

Collection: window.frames

An alternative way to get a window object for – is to get it from the named collection window.frames :

  • By number: window.frames[0] – the window object for the first frame in the document.
  • By name: window.frames.iframeName – the window object for the frame with name=»iframeName» .
 

An iframe may have other iframes inside. The corresponding window objects form a hierarchy.

  • window.frames – the collection of “children” windows (for nested frames).
  • window.parent – the reference to the “parent” (outer) window.
  • window.top – the reference to the topmost parent window.
window.frames[0].parent === window; // true

We can use the top property to check if the current document is open inside a frame or not:

Читайте также:  Java while до исключения

The “sandbox” iframe attribute

The sandbox attribute allows for the exclusion of certain actions inside an in order to prevent it executing untrusted code. It “sandboxes” the iframe by treating it as coming from another origin and/or applying other limitations.

There’s a “default set” of restrictions applied for . But it can be relaxed if we provide a space-separated list of restrictions that should not be applied as a value of the attribute, like this: .

In other words, an empty «sandbox» attribute puts the strictest limitations possible, but we can put a space-delimited list of those that we want to lift.

Here’s a list of limitations:

allow-same-origin By default «sandbox» forces the “different origin” policy for the iframe. In other words, it makes the browser to treat the iframe as coming from another origin, even if its src points to the same site. With all implied restrictions for scripts. This option removes that feature. allow-top-navigation Allows the iframe to change parent.location . allow-forms Allows to submit forms from iframe . allow-scripts Allows to run scripts from the iframe . allow-popups Allows to window.open popups from the iframe

The example below demonstrates a sandboxed iframe with the default set of restrictions: . It has some JavaScript and a form.

Please note that nothing works. So the default set is really harsh:

Источник

Общение между окнами и фреймами

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Более новая информация по этой теме находится на странице https://learn.javascript.ru/cross-window-communication.

Элемент iframe является обычным узлом DOM, как и любой другой. Существенное отличие – в том, что с ним связан объект window внутреннего окна. Он доступен по ссылке iframe.contentWindow .

Таким образом, iframe.contentWindow.document будет внутренним документом, iframe.contentWindow.document.body – его и так далее.

В старых браузерах использовались другие свойства, такие как iframe.contentDocument и даже iframe.document , но они давно не нужны.

Переход внутрь ифрейма

В примере ниже JavaScript получает документ внутри ифрейма и модифицирует его:

  var iframe = document.getElementsByTagName('iframe')[0]; var iframeDoc = iframe.contentWindow.document; if (iframeDoc.readyState == 'complete') < iframeDoc.body.style.backgroundColor = 'green'; >iframe.onload = function() 

Атрибут src может использовать протокол javascript , как указано выше: src=»javascript:код» . При этом код выполняется и его результат будет содержимым ифрейма. Этот способ описан в стандарте и поддерживается всеми браузерами.

Атрибут src является обязательным, и его отсутствие может привести к проблемам, вплоть до игнорирования ифрейма браузером. Чтобы ничего не загружать в ифрейм, можно указать пустую строку: src=»javascript:»» или специальную страницу: src=»about:blank» .

Читайте также:  Вернуть длину строки php

В некоторых браузерах (Chrome) пример выше покажет iframe зелёным. А в некоторых (Firefox) – оранжевым.

Дело в том, что, когда iframe только создан, документ в нём обычно ещё не загружен.

При обычных значениях iframe src=»https://learn.javascript.ru/» , которые указывают на HTML-страницу (даже если она уже в кеше), это всегда так. Документ, который в iframe на момент срабатывания скрипта iframeDoc – временный, он будет заменён на новый очень скоро. И работать надо уже с новым документом iframeDoc2 – например, по событию iframe.onload .

В случае с javascript -протоколом, по идее, ифрейм уже загружен, и тогда onload у него уже не будет. Но здесь мнения браузеров расходятся, некоторые (Firefox) всё равно «подгрузят» документ позже. Поэтому факт «готовности» документа в скрипте проверяется через iframeDoc.readyState .

Ещё раз заметим, что при обычных URL в качестве src нужно работать не с начальным документом, а с тем, который появится позже.

Кросс-доменность: ограничение доступа к окну

Элемент является «двуличным». С одной стороны, это обычный узел DOM, с другой – внутри находится окно, которое может иметь совершенно другой URL, содержать независимый документ из другого источника.

Внешний документ имеет полный доступ к как к DOM-узлу. А вот к окну – если они с одного источника.

Это приводит к забавным последствиям. Например, чтобы узнать об окончании загрузки , мы можем повесить обработчик iframe.onload . По сути, это то же самое что iframe.contentWindow.onload , но его мы можем поставить лишь в случае, если окно с того же источника.

  

Если бы в примере выше был с текущего сайта, то оба обработчика сработали бы.

Иерархия window.frames

Альтернативный способ доступа к окну ифрейма – это получить его из коллекции window.frames .

Обратим внимание: в коллекции хранится именно окно ( contentWindow ), а не DOM-элемент.

Демонстрация всех способов доступа к окну:

   

Внутри ифрейма могут быть свои вложенные ифреймы. Всё это вместе образует иерархию.

Ссылки для навигации по ней:

  • window.frames – коллекция «детей» (вложенных ифреймов)
  • window.parent – содержит ссылку на родительское окно, позволяет обратиться к нему из ифрейма. Всегда верно:
// (из окна со фреймом) window.frames[0].parent === window; // true
window.frames[0].frames[0].frames[0].top === window

Свойство top позволяет легко проверить, во фрейме ли находится текущий документ:

Песочница sandbox

Атрибут sandbox позволяет построить «песочницу» вокруг ифрейма, запретив ему выполнять ряд действий.

  • Заставляет браузер считать ифрейм загруженным с другого источника, так что он и внешнее окно больше не могут обращаться к переменным друг друга.
  • Отключает формы и скрипты в ифрейме.
  • Запрещает менять parent.location из ифрейма.

Пример ниже загружает в документ с JavaScript и формой. Ни то ни другое не сработает:

Источник

Оцените статью