When your browser opens a web page, it enforces various security rules. The most important one is the same-origin policy. It defines access rules for dynamic scripts and is considered to be the cornerstone of the web security model. The concept is rather old, it is from 1995 when Netscape Navigator 2 owned the streets of the web. Chances are, you two have already met during your development career, so no need for introductions. Let’s get right to it.
Before we dive into the policy and what it enforces, we need to understand what these so called origins are. When the browser loads a page it automatically assigns the document an origin. The origin is a tuple consisting of three parts: scheme, host/domain, and port. Origins can be inherited and even changed within certain limits. There is also a special origin called opaque origin, which is used to create unique, sandboxed security contexts.
To add to the complexity not only documents have origins. Images, scripts, fonts, and anything handled by the browser has an origin dynamically attached to it at runtime. Runtime is important! Intuitively the same image hosted on different domains will have different origins when rendered!
Think of origins as labels which will be used to authenticate future critical operations.
It is rather simple: No cooperation can take place between entities having distinct origins. Here is what this means in practice:
- Loading a page with different origin using AJAX will fail!
- Reading pixel data from a tainted canvas (ie. it has an image from another origin) will fail!
- Manipulating an IFRAME’s content cross-origin will fail!
- Accessing the local/session storage of another origin… wait, there isn’t even an API for that!
Naturally, with every policy there are exceptions. Here is what Mozilla says about them:
Cross-origin writes are typically allowed. Cross-origin embedding is typically allowed.
As you have probably guessed by now, exceptions do create some problems. Here is a well-crafted sample of what data is leaked because of cross-origin embedding. Another great example is Cross Site Request Forgery, which is partially made possible because of cross-origin writes. I’ll cover this in another post.
These “policy violations” are required to run the current state of the web. Let’s see what we can do to relax the policy even more. After all, rules are in the way of innovation right?
Relaxing the same origin policy
Cross-origin cooperation is required for the web. Period. Luckily, the only thing we need to do is explicitly enable this. This is possible by using the so-called CORS headers. Currently this is widely supported. Back when support was not so widespread, there was JSONP. Some consider JSONP to be a “hack” around the same origin policy. However, if we take a closer look, it does not seem so. JSONP requires explicit server cooperation, which is, although not as granular, essentially the same as CORS.
To cooperate between IFRAMEs of different origin we can use window.postMessage().
The same origin policy defines one of the first security features enforced by browsers. It is a fundamental part of today’s security model and its role is more important than ever. The gist of it is preventing cooperation between different origins. It cannot be disabled, nor should you attempt it as that compromises security significantly.
Modern web applications require such cooperation, and they can explicitly declare support for cross-domain activities.
Besides providing a basic level of security, this policy can be used strategically to enhance it greatly. As a great example, GitHub spreads the content they serve over several domains to efficiently sandbox them.
Next time you encounter the same-origin policy in action, greet it with a smile and respect your browser for obeying it. You are old friends, after all…