Cross origin javascript embedding

JavaScript 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:

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

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 , 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

  • iframe.contentWindow for accessing the window within the .
  • iframe.contentDocument for getting the document within . 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 from another origin:

html> html> head> title>Title of the Document title> 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 .
Читайте также:  Php datetime interval format

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

html> html> head> title>Title of the Document title> head> body> iframe id="iframe" src="/"> iframe> script> iframe.onload = function( ) < // just do anything iframe.contentDocument.body.prepend("Welcome to W3Docs"); >; 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 iframe 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:

html> html> head> title>Title of the Document title> 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:

html> html> head> title>Title of the Document title> 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 .

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

Let’s take a look at an example:

html> html> head> title>Title of the Document title> 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.

So, with it, a window from david-brown.com can exchange information with gmail.com, but only when they both agree and call the matching JavaScript functions.

It makes the operation safe for users.

The interface includes two parts that are postMessage and onmessage.

PostMessage

The psotMessage method is called when the window intends to send a message. That is, when you need to send a message to win, you need to call win.postMessage(data, targetOrigin) .

It includes the following arguments:

  • data: it includes the data to send. A structured cloning algorithm is used to clone data.
  • targetOrigin: it indicates the target window origin. So, only a window from a particular origin will receive the message.

Let’s check out an example:

html> html> head> title>Title of the Document title> head> body> iframe src="http://example.com" name="example"> script> let win = window.frames.example; win.postMessage("message", "http://example.com"); script> body> html>

Also, you can set targetOrigin to * if the check is not necessary for you:

html> html> head> title>Title of the Document title> head> body> iframe src="http://example.com" name="example"> script> let win = window.frames.example; win.postMessage("message", "*"); script> body> html>

Onmessage

The target window must have a handler on the message event to get a message. It occurs once postMessage is called.

The properties of the event object are as follows:

  • data: the postMessage data.
  • origin: the sender origin. For instance, https://www.w3docs.com/.
  • source: a reference to the window of the sender.

Here, addEventListener should be applied for assigning the handler.

The window.onmessage syntax will not operate.

The example will look like this:

window.addEventListener("message", function (event) < if (event.origin != 'http://javascript.info') < // something from an unknown domain, let's ignore it return; > alert("received: " + event.data); // can message back using event.source.postMessage(. ) >);

Summary

For calling methods and accessing another window content, a reference is necessary.

The following references are used for popups:

In case the windows have the same origin, they can do anything to one another. Otherwise, it’s only possible to change the location and post a message to it.

The postMessage interface helps two windows with different origins to interact.

  1. The targetWin.postMessage(data, targetOrigin) is called by the sender.
  2. If targetOrigin is not ‘*’, then the browser checks whether there is targetOrigin in the targetWin window.
  3. If it’s there, the message event is triggered by the targetWin .

Источник

Same-origin policy

Mariko Kosaka

The same-origin policy is a browser security feature that restricts how documents and scripts on one origin can interact with resources on another origin.

A browser can load and display resources from multiple sites at once. You might have multiple tabs open at the same time, or a site could embed multiple iframes from different sites. If there is no restriction on interactions between these resources, and a script is compromised by an attacker, the script could expose everything in a user’s browser.

The same-origin policy prevents this from happening by blocking read access to resources loaded from a different origin. «But wait,» you say, «I load images and scripts from other origins all the time.» Browsers allow a few tags to embed resources from a different origin. This policy is mostly a historical artifact and can expose your site to vulnerabilities such as clickjacking using iframes. You can restrict cross-origin reading of these tags using a Content Security Policy.

What’s considered same-origin? #

An origin is defined by the scheme (also known as the protocol, for example HTTP or HTTPS), port (if it is specified), and host. When all three are the same for two URLs, they are considered same-origin. For example, http://www.example.com/foo is the same origin as http://www.example.com/bar but not https://www.example.com/bar because the scheme is different.

What is permitted and what is blocked? #

Generally, embedding a cross-origin resource is permitted, while reading a cross-origin resource is blocked.

iframes Cross-origin embedding is usually permitted (depending on the X-Frame-Options directive), but cross-origin reading (such as using JavaScript to access a document in an iframe) isn’t.
CSS Cross-origin CSS can be embedded using a &LTlink> element or an @import in a CSS file. The correct Content-Type header may be required.
forms Cross-origin URLs can be used as the action attribute value of form elements. A web application can write form data to a cross-origin destination.
images Embedding cross-origin images is permitted. However, reading cross-origin image data (such as retrieving binary data from a cross-origin image using JavaScript) is blocked.
multimedia Cross-origin video and audio can be embedded using &LTvideo> and &LTaudio> elements.
script Cross-origin scripts can be embedded; however, access to certain APIs (such as cross-origin fetch requests) might be blocked.

A webpage on the web.dev domain includes this iframe:

iframe id="iframe" src="https://example.com/some-page.html" alt="Sample iframe"></iframe>

The webpage’s JavaScript includes this code to get the text content from an element in the embedded page:

const iframe = document.getElementById('iframe');
const message = iframe.contentDocument.getElementById('message').innerText;

Is this JavaScript allowed?

No. Since the iframe is not on the same origin as the host webpage, the browser doesn’t allow reading of the embedded page.

A webpage on the web.dev domain includes this form:

form action="https://example.com/results.json"> 
label for="email">Enter your email: </label>
input type="email" name="email" id="email" required>
button type="submit">Subscribe</button>
</form>

Can this form be submitted?

Yes. Form data can be written to a cross-origin URL specified in the action attribute of the &LTform> element.

A webpage on the web.dev domain includes this iframe:

iframe src="https://example.com/some-page.html" alt="Sample iframe"></iframe>

Is this iframe embed allowed?

Usually. Cross-origin iframe embeds are allowed as long as the origin owner hasn’t set the X-Frame-Options HTTP header to deny or sameorigin .

A webpage on the web.dev domain includes this canvas:

canvas id="bargraph"></canvas>

The webpage’s JavaScript includes this code to draw an image on the canvas:

var context = document.getElementById('bargraph').getContext('2d');
var img = new Image();
img.onload = function()
context.drawImage(img, 0, 0);
>;
img.src = 'https://example.com/graph-axes.svg';

Can this image be drawn on the canvas?

Yes. Although the image is on a different origin, loading it as an img source does not require CORS. However, accessing the binary of the image using JavaScript such as getImageData , toBlob or toDataURL requires an explicit permission by CORS.

How to prevent Clickjacking #

An attack called «clickjacking» embeds a site in an iframe and overlays transparent buttons which link to a different destination. Users are tricked into thinking they are accessing your application while sending data to attackers.

To block other sites from embedding your site in an iframe, add a content security policy with frame-ancestors directive to the HTTP headers.

Alternatively, you can add X-Frame-Options to the HTTP headers see MDN for list of options.

Wrap up #

Hopefully you feel a little relieved that browsers work hard to be a gatekeeper of security on the web. Even though browsers try to be safe by blocking access to resources, sometimes you want to access cross-origin resources in your applications. In the next guide, learn about Cross-Origin Resource Sharing (CORS) and how to tell the browser that loading of cross-origin resources is allowed from trusted sources.

Источник

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