December 13th, 2012 | Ken Payson
Understanding the Web-Same Origin Policy, Restrictions, Purpose, and Workarounds
Sooner or later every developer will have to get or send data from his or her site to a site on a different domain. Recently, I was working on a bookmarklet which required communication between my company’s site and another domain. Whenever there is web communication between two different domains, it is necessary to understand the same origin policy of the web. Wikipedia summarizes the same origin policy as
“The policy permits scripts running on pages originating from the same site to access each other’s methods and properties with no specific restrictions, but prevents access to most methods and properties across pages on different sites.”
The thing to know and understand is that there are two origin policies. The “DOM Origin Policy” governs reading/writing via the DOM information in different windows. The “XmlHttpRequest Origin Policy” governs Ajax communications between different windows.
DOM Same Origin Policy
The same origin policy for the DOM disallows reading from or writing to a window if the window’s location is on a different domain. This prevents a number of attacks which could be used to steal user information. A simple example would be:
- MaliciousSite.com has a link on its page to mybank.com
- MaliciousSite.com could then read and write to mybank.com through a reference to the mybank.com window.
XmlHttpRequest Same Origin Policy
When an HTTP request is made, the web browser will send the cookies belonging to the requested domain. In particular, sites typically use an authentication cookie which proves that you are logged in to a site. Based on this, if there were no XmlHttpRequest Origin Policy, a CSRF attack could work as follows:
- User navigates to a bad site MaliciousSite.com
- MaliciousSite.com makes the blind guess that the user is also logged in on another tab to MyBank.com
- MyBank.com exposes data via web services to authenticated users.
- MaliciousSite.com uses the web services of MyBank.com to obtain information. The web services on MyBank.com return the requested data because the user is authenticated and the authentication cookie was sent with the Ajax request.
Just as there are “two” origin policies, there are two corresponding sets of “workarounds” which allow for communication between windows. Let’s take a look at these methods and see how they allow for legitimate communication without reintroducing the same security holes.
Working around the DOM Same Origin Policy
- Get a reference to the window which you want to communicate with ex var win = window.frames.window
- The window receiving messages sets up an event listener for the messages that will be sent.
- The sender calls win.postmessage(dataMessage).
- For two way communication, event listeners are set up on both sides.
Window.post message does not allow for unauthorized sharing of information. Using window.postmessage requires both sides to be in cooperation on the messages structure and it requires the message recipient to accept messages coming from the sender. Using the earlier example, myBank.com would never be expecting messages from mybank.com and so even if mybank.com did have an event listener set up and methods for data sharing it would certainly ignore messages coming from any unknown location.
Working around the XmlHttpRequest Same Origin Policy
To work around the XMLHttp Origin Policy there are a few different options. The first thing you could do, if you want to use a data service from another domain, is simply create a proxy service on your site which calls the service on the other domain and passes back the data. This involves extra server side coding on your part, but it also requires no cooperation from the other domain. The next techniques that I will mention involve cooperation from the other domain in how their web services are set up. If the other domain isn’t “cooperating,” writing a proxy service maybe your only option.
CORS is a relatively new standard that address the need for cross domain Ajax in a more proper fashion. CORS stands for Cross Origin Request Sharing. All modern browsers can make Ajax requests to other domains so long as the target server allows it. A security handshake takes place using HTTP headers. When the client makes a cross-origin request, it includes the HTTP header – Origin – which announces the requesting domain to the target server. If the server wants to allow the cross-origin request, it has to echo back the Origin in the HTTP response header – Access-Control-Allow-Origin. The target server can establish a security policy to accept requests from anywhere or to only accept requests from specific domains. On the client, jQuery Ajax automatically supports CORS for cross domain requests. So, no additional coding on the client is necessary if you are using jQuery. We can see that CORS also makes CSRF attacks highly unlikely. If a site is checking for an authentication token with its web services, it will certainly not add an origin header for an untrusted domain.
I hope that you found this brief introduction helpful. Understanding the rhyme and reason for the same origin policy should make the learning process easier when it comes time to dive into implementation details. Happy coding!