Classically, browsers constrain network requests to the same-origin, which prevent web applications running from one origin to obtain data from another origin and limit unsafe HTTP requests which direct towards destinations different from running application’s origin.
When such cross-origin request behavior is desired, user credentials are required (including HTTP authentication and cookies).
The HTML5 specification extends support for cross-origin resource sharing as under:
1. Response can include Access-Control-Allow-Origin header with a value of where the request originated from. Once validates, this will allow access to resource’s content.
2. Browsers (user agents) can discover whether a cross-origin resource is ready to accept requests from a specific origin.
3. Server side applications can discover via the Origin header, whether an HTTP request is considered a cross-origin request.
Let us see how this plays out. Consider an example where the user is accessing foo.com, and foo.com needs to access bar.com. To support such a cross-origin request, a browser sends a cross-origin request to bar.com with the Origin HTTP header value of foo.com.
Request to bar.com with header Origin: foo.com
If bar.com allows the request, it respond with “Access-Control-Allow-Origin” header in its response and a value of permitted origin sites. The browser will now evaluate whether the origin site matches the value in the permitted sites.
Response from bar.com with header Access-Control-Allow-Origin : foo.com (if foo.com is permitted)
If cross-origin resource sharing is permitted, the access to the resource is made as under.
An object of XMLHttpRequest is made and a GET call is made to the bar.com domain as under:
var myXMLHttpRequest = new XMLHttpRequest()
myXMLHttpRequest.open(“GET”, “http://bar.com”)
myXMLHttpRequest.onreadystatechange = function() { /* code which is executed every time the readyState property changes */ }
myXMLHttpRequest.send()
In certain scenarios, establishing cross-origin requests might not be as simple as above. In such cases, appropriate access control headers needs to be used to understand how to submit the request.
The various response headers (not a comprehensive list) for resource sharing are:
1. Access-Control-Allow-Origin – This has been discussed above. This indicates whether a resource can be shared (determined by value of Origin request header).
2. Access-Control-Allow-Credentials – This header represents whether the response to the request can exposed when omit credential flag is not set.
3. Access-Control-Expose-Headers – This header indicates which headers are safe to expose to APIs.
4. Access-Control-Max-Age – this header represents how long to cache a response (to prevent preflight requests to be made while the cache is valid.
5. Access-Control-Allow-Methods – this header indicates the methods which can be used in an actual request.
6. Access-Control-Allow-Headers – this header indicates, as part of response to a preflight request which header field names can be used in a request.
The support for cross-origin resource sharing should be used wisely.
An example of misuse is when the response to cross-origin request is if the response states that it can accept origin requests from any server when the resource is not to be publicly shared. When this happens (Access-Control-Allow-Origin header value of *), it means that user tokens will be directly shared with the destination server. This can represent a security issue.
Most of the modern browsers support Cross-origin resource sharing.
Summary
In this article, we learned about Cross-origin resource sharing and how to use XMLHttpRequest to get access to a shared resource.
About the author
Vipul Patel is a Program Manager currently working at Amazon Corporation. He has formerly worked at Microsoft in the Lync team and in the .NET team (in the Base Class libraries and the Debugging and Profiling team). He can be reached at vipul.patel@hotmail.com