Skip to content

Instantly share code, notes, and snippets.

@GAKINDUSTRIES
Last active March 6, 2018 05:01
Show Gist options
  • Save GAKINDUSTRIES/ad19ed285d6ec07c688336cb78fea670 to your computer and use it in GitHub Desktop.
Save GAKINDUSTRIES/ad19ed285d6ec07c688336cb78fea670 to your computer and use it in GitHub Desktop.
Same origin policy, why is it so important?

Today is time to learn something about same-origin-policy and why it is so important to know when building a website. We will go through iframes too and what measures you have to take into account when using them. Hope you like it :D

What is it ?

The Same-Origin-Policy is an important concept in the web application security model. Under the policy, a web browser permits scripts contained in a first web page to access data in a second web page, but only if both web pages have the same origin. An origin is defined as a combination of URI scheme, hostname, and port number. This policy prevents a malicious script on one page from obtaining access to sensitive data on another web page through that page's Document Object Model.

This is the common definition that we will found on every page. But what really is it. Well, basically Same Origin Policy limits the access of one window to another.

The reason behind that is security. If you have https://GAKINDUSTRIES.com in one window and https://gmail.com in another one, then you’d not want a script from http://blabla.com to access or modify your mail or run actions in context of gmail on your behalf.

The essence of the Same Origin policy can be formulated as: windows can work in contexts of each other only if they are from same protocol://domain:port, or, shortly, from same origin.

Notice that the path part of the URL does no matter anything.

As an example look at the following URL that belongs to the same origin:

On the other hand, the following URL's does NOT belongs to the same origin:

Changing origin

An important exception for the Same Origin policy are third-level domains.

A page may change its own origin with some limitations. A script can set the value of document.domain to its current domain or a superdomain of its current domain. If it sets it to a superdomain of its current domain, the shorter domain is used for subsequent origin checks. For example, say we’ve got a window at a http://GAKINDUSTRIES.com and two iframes: the first comes from http://guille.GAKINDUSTRIES.com and another one comes from http://john.GAKINDUSTRIES.com.

Now if both sites assign:

document.domain = 'GAKINDUSTRIES.com'

Then, the Same Origin restrictions will be removed.

However GAKINDUSTRIES.com could NOT set document.domain to othercompany.com since that is not a superdomain of company.com

So, the document.domain allows different 3rd level domains to communicate with each other and with their common 2nd level domain.

Why is the same origin policy important?

Assume you are logged into Facebook and visit a malicious website in another browser tab. Without the same origin policy JavaScript on that website could do anything to your Facebook account that you are allowed to do. For example read private messages, post status updates, analyse the HTML DOM-tree after you entered your password before submitting the form.

But of course Facebook wants to use JavaScript to enhance the user experience. So it is important that the browser can detect that this JavaScript is trusted to access Facebook resources. That's where the same origin policy comes into play: If the JavaScript is included from a HTML page on facebook.com, it may access facebook.com resources.

Now replace Facebook with your online banking website, and it will be obvious that this is an issue.

Why is the same origin policy important?

Assume you are logged into Facebook and visit a malicious website in another browser tab. Without the same origin policy JavaScript on that website could do anything to your Facebook account that you are allowed to do. For example read private messages, post status updates, analyse the HTML DOM-tree after you entered your password before submitting the form.

But of course Facebook wants to use JavaScript to enhance the user experience. So it is important that the browser can detect that this JavaScript is trusted to access Facebook resources. That's where the same origin policy comes into play: If the JavaScript is included from a HTML page on facebook.com, it may access facebook.com resources.

Now replace Facebook with your online banking website, and it will be obvious that this is an issue.

How does cross domain communication work?

The same origin policy is not enforced for all requests. Among others the <script> and <img> tags may fetch resources from any domain. Posting forms and linking to other domains is possible, too. Frames and iframes way display information from other domains but interaction with that content is limited.

There are some approaches to allow XMLHttpRequest (ajax) calls to other domains in a secure way, but they are not well supported by common browsers. The common way to enable communication with another domain is JSONP. Please read more about JSONP here.

Cannot get but can set

The important fact is that it is not allowed to read from another origin, but some properties are writable. The most notable one is location.

From the example above we’ve seen that browser protects location of the window from different origin from being red. But we can set it:

<iframe src="http://google.com" name="google" style="height:100px"></iframe>

<script>
document.getElementsByName('google')[0].onload = function() {
  frames[0].location = 'http://wikipedia.org'
  alert('Changed to wikipedia')
}
</script>

The example above, when run, will change the location.

Note, changing location.href will not work, because there is no read access to location properties. Only direct set works.

Now let's stay in iframes for a moment and talk a little bit about them.

Why iframes ?

Everywhere you look, you see embedded YouTube videos, tweets, like buttons, etc.

All of these things are embedded via iframes, or at least should be. Browsers keep the context of the iframe and its parent document totally separate by default. Neither the parent document nor the iframe document has access to each other's DOM, CSS styles, or JavaScript functions if they're not from the same domain. If the iframe document overrides a String.prototype function, for example, the parent document won't see this override. If a parent document tries to style its iframe's contents with something like the following, nothing will happen.

iframe p { color: green }

Also, neither the iframe nor its parent can access the other's cookies or local storage. The browser effectively treats them like separate tabs. If, alternatively, you add a '+1' or 'like' button on your page by pasting some third-party JavaScript directly on your page, that separation is no longer there. Surprisingly, Google only offers the "embed our JavaScript in your site" option for its +1 button, and a "you're on your own" policy if you want to embed it as a hosted iframe, which you would have to host.

Any third-party code that you add directly to your site without the protection of iframes would have all of the same access as your own code. Iframes are the way to go.

So what's the matter with them ???

If you embed an iframe from your own domain, the browser does not provide any protections against it. Presumably, this is safe since it is your own domain and you likely trust (or wrote) this code. If the iframe comes from a different domain, a browser's cross-domain policy would kick in, preventing the iframe from accessing cookies, local storage, or the DOM from its embedding document. Even so, cross-domain iframes still have the ability to trigger alerts, run plugins (malicious or otherwise), autoplay videos, and present submittable forms in an attempt to phish users' information. If all you want the iframe to be able to do is present a social network button, there should be a mechanism to prevent it from doing much else. Thankfully, the ability to restrict iframes is supported by IE 10, Firefox, Chrome, and Safari. It's called the sandbox attribute.

<iframe sandbox src="http://example.com"></iframe>

With this attribute set, the document inside the iframe cannot do any of the following:

  • Run any JavaScript, even if it would only affect contents of the iframe.
  • Change the parent's URL
  • Open pop-ups, new windows, or new tabs
  • Submit forms
  • Run plug-ins
  • Use pointer lock
  • Read cookies or local storage from the parent, even if it's from the same origin

This is a good starting point for securing an iframe. Then, as you determine what things it needs to perform its normal functions, you can enable just those features. The sandbox attribute gives us this capability, by allowing you to specify a space-separated list of permissions, with one or more of the following choices.

  • allow-same-origin - allows the iframe to access cookies and local storage from the parent, as if it came from the same domain.
  • allow-top-navigation - allows the iframe to navigate the parent to a different URL.
  • allow-forms - allows form submission
  • allow-scripts - allows JavaScript execution
  • allow-popups - allows the iframe to open new windows or tabs
  • allow-pointer-lock - allows pointer lock

Be careful about giving the iframe too much power. If you sandbox the iframe but give it the permissions allow-same-origin and allow-scripts, the iframe can now run JavaScript and access your DOM, and it could easily use this power to remove its own sandbox attribute and reload itself with no restrictions.

Things get worse using SEAMLESS !!

By default, an embedded iframe has an 2px inset border around it. If you don't like it, you may have been tempted to use a new HTML5 iframe attribute called seamless to get rid of it. (It's so new, only the latest version of Safari and Chrome support it as of this writing.)

<iframe seamless src="http://example.com"></iframe>

A few top Google search results for "iframes without borders" suggest using this hot new iframe attribute as the way to make iframes look, well, seamless. Unfortunately, this attribute does way, way more than remove borders. A seamless iframe has access to all of the following from the parent document:

  • CSS styles
  • JavaScript functions and objects
  • The whole DOM
  • Ability to change the parent's URL. (In fact, all links in the iframe navigate the parent frame by default.)

The iframe gets access to all of these things even if it is cross-origin. In essence, a seamless iframe acts as if it's just part of the parent document, and it is granted the same level of trust and power. Sure, the borders are removed, but so is any security the iframe provided in the first place. If all you want is for your iframe to look seamless—without any borders or scrollbars—there is a way to do that without handing over complete control of your website to a third-party. Just use CSS.

<iframe src="http://example.com" allowTransparency="true" scrolling="no" frameborder="0" style="border:none; overflow:hidden;"></iframe>

Only use the seamless attribute if you trust the iframe's content as if it were your own.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment