Cross-window Communication

Cross-window Communication

Cross-window Communication


The Same Origin policy restricts the windows access to one another. That means, if a user has opened two pages: the first one from daivd-brown.com and the second one - gmail.com, then they couldn't want a script from daivd-brown.com for reading a mail from gmail.com. The purpose of such a policy is to protect users from information theft.

Describing the Same Origin

Two URLs are considered to have the same origin when their protocol, domain, and port are the same.

Here are examples of same-origin URLs:

  • http://oursite.com
  • http://oursite.com/
  • http://oursite.com/my/page.html

Now, let’s see examples of URLs that don’t have the same origin:

  • http://site.org
  • http://www.site.com
  • https://site.com
  • http://site.com:8080

According to the Same Origin policy:

  • In case of having a reference to another window ( for example, a popup created with or a window inside <iframe>, and the window is from the same origin, then complete access to that window is provided.
  • In another way, in case of coming from another origin, then the content of the window can’t be accessed. Only the location can be an exception: it can be modified. But, the location can’t be read.

iFrame

The <iframe> tag can host an independent embedded window that has its window and document objects. They can be accessed with the following properties:
  • iframe.contentWindow for accessing the window within the <iframe>.
  • iframe.contentDocument for getting the document within <iframe>. It’s a shorthand for iframe.contentWindow.document.

While accessing something inside the embedded window, the browser inspects whether the iframe has the same origin. Otherwise, access will be denied. In the example below, you can see an attempt to read and write to <iframe> from another origin:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <iframe id="iframe" src="https://example.com"></iframe>
    <script>
      iframe.onload = function() {
        // get the reference to the inner window
        let iframeWindow = iframe.contentWindow; // OK
        try {
          //but not to the document inside it
          let doc = iframe.contentDocument; // ERROR
        } catch(err) {
          alert(err); // Security Error, another origin
        } 
        // also we cannot READ the page  URL in the iframe
        try {
          // Cannot read URL from Location object
          let href = iframe.contentWindow.location.href; // ERROR
        } catch(err) {
          alert(err); // Security Error
        } 
        //can be WRITE to a location (and therefore load something else in the iframe)
        iframe.contentWindow.location = '/'; // OK 
        iframe.onload = null; // clear the handler so that it does not start after changing the location
      };
    </script>
  </body>
</html>

But this code will lead to errors in all circumstances except:

  • Receiving the reference to the inner window iframe.contentWindow .
  • While writing to the location .

Differently, when the <iframe> has the same origin, anything can be done with it, like here:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <!-- iframe from the same site -->
    <iframe id="iframe" src="/"></iframe> 
    <script>
      iframe.onload = function() {
        // just do anything
        iframe.contentDocument.body.prepend("Welcome to Web");
      };
    </script>
  </body>
</html>

Windows on Subdomains: document.domain

So, by default two URLs that have different domains have different origins. But, when windows have the same second-level domain, it is possible to make the browser ignore the difference.

The following code should be run to make it work:

document.domain = 'oursite.com';

Iframe: wrong document pitfall

If the frame is from the same origin with a possibility of accessing its document, then there exists a pitfall. It is an essential thing to know but doesn’t relate to cross-origin requests.

So, doing something with the document at once will be lost:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <iframe id="iframe" src="/" ></iframe>
    <script>
      let oldDocs = iframe.contentDocument;
      iframe.onload = function() {
        let newDocs = iframe.contentDocument;
        // the loaded document is different from the original
        alert(oldDocs == newDocs); // false
      };
    </script>
  </body>
</html>

That’s the wrong document. Setting any event handlers on it will be ignored. The right document is where iframe.onload occurs. However, it occurs only when the total iframe with all the resources is loaded.

With setInterval the moment can be caught earlier, like here:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <iframe id="iframe" src="/" ></iframe>
    <script>
      let oldDocs = iframe.contentDocument;
      // every 100 ms  we check if the document is new 
      let timer = setInterval(() => {
        let newDocs = iframe.contentDocument;
        if (newDocs == oldDocs) return;
        alert("New document is here");
        clearInterval(timer); // cancel setInterval, no longer needed
      }, 500);
    </script>
  </body>
</html>

Window.frames

There is an alternative option of getting a window object for <iframe>.

You can get it from the named collection window.frames :

  1. By number window.frames[0] .
  2. By name window.frames.iframeName.

Let’s take a look at an example:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <iframe id="iframe" src="/" style="height:100px" name="win"></iframe>
    <script>
      alert(iframe.contentWindow == frames[0]); // true
      alert(iframe.contentWindow == frames.win); // true
    </script>
  </body>
</html>

Cross-window Messaging

Windows can talk to each other no matter what origin they have, with the help of the postMessage interface.

Reactions

Post a Comment

0 Comments

close