Working With and Around the Same-Origin Policy

Share this article

As a JavaScript developer, you likely use Ajax extensively to exchange data with a server or update a web page without refreshing. Although sending an Ajax request to your server is a pretty straight forward request, exchanging data with a server on another domain is a different story altogether. Let us try it out! Let us run the following from http://www.mysite.com (or 127.0.0.1 / localhost) on Chrome 32.

request = new XMLHttpRequest;
request.open('GET', 'http://myothersite.com/', true);
request.send();
You will receive an error. XMLHttpRequest cannot load http://myothersite.com/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin http://www.mysite.com is therefore not allowed access. Why does this happen? Didn’t we do everything right?

Same-origin Policy

The same-origin policy permits scripts running in a browser to only make requests to pages on the same domain. This means that requests must have the same URI scheme, hostname, and port number. This post on the Mozilla Developer Network clearly defines the definition of an origin and when requests result in failure. If you send a request from http://www.mysite.com/, the following types of requests result in failure.
  • https://www.mysite.com/ – Different protocol (or URI scheme).
  • http://www.mysite.com:8080/myUrl – Different port (since HTTP requests run on port 80 by default).
  • http://www.myothersite.com/ – Different domain.
  • http://mysite.com/ – Treated as a different domain as it requires the exact match (Notice there is no www.).

Changing Origin

Occasionally, the same origin policy may block requests between subdomains on the same domain. The easiest way to solve this problem is to set document.domain from within JavaScript. For example:
document.domain = 'mysite.com';
Note that the port number is stored separately. Making one domain interact with another on a different port (which is the case with chat applications), would require something different. Even setting document.domain = document.domain, which overwrites the port number to null will not help in getting this done.

Using a Web Proxy

Although specifying document.domain helps you contact subdomains of your own website, what would you do if you needed to access data from a different domain altogether? An interesting, yet easy to understand, approach is to use a web proxy on your own server. Instead of sending a request directly from your domain (http://www.mysite.com/) to a new domain (http://www.myothersite.com/), you instead send a request to your own server (http://www.mysite.com/connect/), which in turns sends a request to the new domain (http://www.myothersite.com/). To the browser, it appears you are exchanging the data with your own server. In reality, in the background, you have accessed data on a new domain from your server. A flowchart to explain the process is shown below. alt text Source: Yahoo Developers

Using JSONP

Another way of implementing cross browser requests is by using JSONP, or “JSON with padding.” JSONP takes advantage of the fact that <script> tags are not subject to the same-origin policy. For example, you can include a library like jQuery on your page even if it is hosted on Google’s CDN. JSONP requests are made by dynamically requesting a <script> tag. The interesting part is that the response is JSON wrapped in a function call. When making the request, you specify the function name as a callback function. When the server responds, the callback function (which must exist on your page) is executed with the data returned from the server. For example, a typical JSON response might look like this:
{
  "id": "123",
  "name": "Captain Jack Sparrow"
}
The same response can be emulated in a script tag with the callback function myFunction as shown below.
<script src="http://www.myothersite.com/get_data?callback=myFunction"></script>
The browser downloads the data from the specified URL normally and evalutates it as JavaScript. The response might look like this:
myFunction({"id": "123", "name": "Captain Jack Sparrow"});
myFunction
would then be invoked, allowing your page to process the JSON returned from myothersite.com.

Security Concerns – Cross Site Request Forgery

Since the <script> tag doesn’t respect the same-origin policy, it is possible for a malicious website to get sensitive data using the same URL. Using the example above, a malicious page could download the same JSON data and perform some unkind act with it. This is known as a Cross Site Request Forgery (CSRF) attack. Some countermeasures to prevent CSRF attacks include using tokens or cookies for validation, and limiting the lifetime of such tokens.

Cross Domain Resource Sharing

Although JSONP can be used to accomplish most tasks with relative ease, there are several shortcomings. You can only send HTTP GET requests using JSONP. This rules out any possibility of doing CRUD operations cleanly using JSONP. Although this security concern is eliminated with the proxy method, there is another interesting method that will help us interact with RESTful APIs without jumping through hoops. Cross Domain Resource Sharing, or CORS, works by modifying HTTP headers in your requests to access resources on a different domain. In IE8+, simple CORS requests using the XDomainRequest (instead of the XMLHttpRequest) are permitted. A simple example is shown below.
request = new XDomainRequest();
request.open(method, url);
request.onload = function() {
  callback(req.responseText);
};
request.send(data);
We have been talking about “simple” requests. Not-so-simple requests refer to preflighted requests, which first send an HTTP request to the other domain to determine whether it is safe to perform that action. A detailed example of a preflighted request and the information exchange between the server and client is explained in this MDN post on CORS.

Conclusion

Although CORS looks like the future of front end programming, you should still use it with care because there is no support for very old browsers (IE7 and earlier). Support for CORS is a minor concern, but you should definitely go ahead and give it a try! For further reading, I suggest you go through MDN’s detailed post on CORS.

Frequently Asked Questions (FAQs) about Same-Origin Policy

What is the Same-Origin Policy and why is it important?

The Same-Origin Policy (SOP) is a critical security concept implemented in web browsers. It restricts how a document or script loaded from one origin can interact with a resource from another origin. It’s crucial for isolating potentially malicious documents, ensuring they cannot access or interfere with another document’s data or the system’s resources.

How does the Same-Origin Policy work?

SOP works by comparing the origin of the requested resource with the origin of the current page. The ‘origin’ is defined by the scheme (protocol), host (domain), and port of the URL. If all these components match, the Same-Origin Policy allows the request. Otherwise, it’s blocked, preventing potential security breaches.

What are the limitations of the Same-Origin Policy?

While SOP is essential for security, it can limit the functionality of legitimate web applications. For instance, it prevents a site from making requests to a different domain, even if the other domain is willing to provide data. This can hinder the integration of third-party services.

How can I work around the Same-Origin Policy?

There are several methods to work around SOP. These include using Cross-Origin Resource Sharing (CORS), JSONP, or a proxy server. However, these methods should be used with caution as they can potentially expose your site to security risks.

What is Cross-Origin Resource Sharing (CORS)?

CORS is a mechanism that allows many resources (e.g., fonts, JavaScript, etc.) on a web page to be requested from another domain outside the domain from which the resource originated. It provides a secure way to bypass the Same-Origin Policy by including additional HTTP headers.

What is JSONP and how does it help bypass the Same-Origin Policy?

JSONP (JSON with Padding) is a method used to send JSON data without facing the restrictions of the Same-Origin Policy. It works by wrapping the data in a function call, which can be executed as a script, bypassing the SOP.

How does a proxy server help in bypassing the Same-Origin Policy?

A proxy server acts as an intermediary for requests from clients seeking resources from other servers. By making requests to the same origin (the proxy server), which then makes requests to other origins, it can bypass the Same-Origin Policy.

Are there any risks associated with bypassing the Same-Origin Policy?

Yes, bypassing the Same-Origin Policy can expose your site to various security risks, including Cross-Site Scripting (XSS) and data breaches. Therefore, it’s crucial to implement these workarounds securely and responsibly.

Can I disable the Same-Origin Policy in my browser for development purposes?

Yes, most browsers allow you to disable the Same-Origin Policy for development purposes. However, this should never be done in a production environment or on a machine that contains sensitive data, as it would leave the system vulnerable to attacks.

How can I ensure that my site is secure while working around the Same-Origin Policy?

It’s crucial to follow best practices for web security. This includes validating and sanitizing all inputs, implementing HTTPS, using secure cookies, and regularly updating and patching all systems. Additionally, always consider the potential security implications before deciding to bypass the Same-Origin Policy.

Shaumik DaityariShaumik Daityari
View Author

Shaumik is a data analyst by day, and a comic book enthusiast by night (or maybe, he's Batman?) Shaumik has been writing tutorials and creating screencasts for over five years. When not working, he's busy automating mundane daily tasks through meticulously written scripts!

corsjsonp
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week