Ajax Cross Domain Resource Access Using jQuery

Problem

Some time back in our project we faced a problem while making an Ajax call using jQuery. Chrome Browser console had given some weird error message like below when we try to access one of our web page:

When we try to access the same web page in Firefox browser, it doesn’t given any error in console but some parsing error occured.

In our case we were accessing XML as an Ajax request resource. I was curious to check if non XML cross domain resource was successfully loading or not. But finally I realized that it is not going through.

In our Ajax call, requesting domain was not same as requested URL domain.

   $.ajax({
            url: "https://10.11.2.171:81/xxxxxx/xxxxxxx.xml",
            type: "get",                                 
            success: function (response) {
                alert( "Load was performed." );
            },
            error: function (xhr, status) {
                alert("error");
            }
        });  

Sometime its mandatory to have cross domain request, consider the case of web component in a desktop application (file: URIs) or others.

Important: Same-origin policy regulates how one domain document or JavaScript can access other domain’s DOM. Same rule imposed for XMLHttpRequest (Ajax).

Same Origin Policy

Same origin policy restrict access to other domain DOM or other resources due to security concern (talked further in the article). It had been implemented by all of the modern (with bit flexibility in one to more security in others) browser to draw a boundary for scripting languages and mechanism like DOM manipulation and AJAX request.
An origin is decided by schema, host and port of an URL. Let say we have a web page with URL https://www.devhours.com/dir1/nice.html (Schema/Protocol: http ;  host: www.devhours.com ; port : <no port mentioned here>). We are trying to access various URL from this page, we will see, URL is following Same origin policy or not.
URLDescriptionSame Origin Policy
ChromeFirefoxIE
https://www.devhours.com/dir1/nice2.htmlSame Schema & hostYYY
https://www.devhours.com/dir2/nice1.htmlSame Schema & hostYYY
https://username:[email protected]/dir2/nice1.htmlSame Schema & hostYYY
https://www.devhours.com/dir2/nice1.htmlDifferent SchemaNNN
https://www.devhours.com:82/dir2/nice1.htmlDifferent PortNNY
https://devhours.com/dir2/nice1.htmlDifferent hostNNN
https://www2.devhours.com/dir2/nice1.htmlDifferent hostNNN
https://v2.www.devhours.com/dir2/nice1.htmlDifferent hostNNN

IE doesn’t consider different port on same domain and protocol as cross domain request.

We suggest our reader to read the article “Same origin policy for file:URIs” for understanding the same origin policy in case of file based URIs.

Cross Origin Network Access

When we talk about cross domain access failure using Ajax, first thing came in our mind is, why its not working, while we can access cross domain images, css, javascript and other resources in our web page without any problem. We need to understand the process and types of cross origin network access.
There are three different kinds of cross domain network interaction:
  1. Cross origin write interaction: It is typically allowed. E.g. links, redirects and form submissions.
  2. Cross origin embedding: It is typically allowed. For e.g. <img src=””>, we can embed cross domain image.
  3. Cross origin reads. It’s typically not allowed. But we can achieve the read access using cross origin embedding, which is typically allowed. For e.g.You can read the image properties by embedding them.

Cross origin embedding example, taken from Mozilla Developer’s Documentation:

1. JavaScript with <script src=”…”></script>. Error messages for syntax errors are only available for same-origin scripts.
2. CSS with <link rel=”stylesheet” href=”…”>. Due to the relaxed syntax rules of CSS, cross-origin CSS requires a correct Content-Type header. Restrictions vary by browser: IE, Firefox, Chrome, Safari (scroll down to CVE-2010-0051) and Opera.
3. Images with <img>. Supported image formats include PNG, JPEG, GIF, BMP, SVG, …
4. Media files with <video> and <audio>.
5. Plug-ins with <object>, <embed> and <applet>.
6. Fonts with @font-face. Some browsers allow cross-origin fonts, others require same-origin fonts.
7. Anything with <frame> and <iframe>. A site can use the X-Frame-Options header to prevent this form of cross-origin interaction.

How to suppress the same origin policy?

In web app world, same origin policy seems to be restrictive sometime, specially if certain domain deliberately wanted to allow cross domain access or same app have interdependent resources on several domains. There are couple of standard or technique which came handy for solving the Same Origin Policy based restrictions. Let’s have a look on those one at a time:

Change Origin using document.domain property

For enabling the property access of two different domain in iframe or windows user can use document.property.
Let say we have a window with URL https://abc.main.com and another window with URL https://xyz.main.com. Using JavaScript set document.property = "main.com"; in both of the windows.

For all subsequent call page will pass origin test, as the origin will be https://main.com/. Though you can’t set the domain name to anothermain.com, it will be not allowed.

After we set the document.property = "main.com";, port number for the domain get nullified and can create serious problem in some scenarios.

From Mozilla Developer Network:

The port number is kept separately by the browser. Any call to the setter, including document.domain = document.domain causes the port number to be overwritten with null. Therefore one can not make company.com:8080 talk to company.com by only setting document.domain = “company.com” in the first. It has to be set in both so that port numbers are both null.

Cross-Origin Resource Sharing

Cross origin resource sharing is a standard from W3C.

This standard developed a convenient way to notify server regarding origin of request using ORIGIN request header. For e.g. origin= www.google.com or origin = null. In response HTTP server can send their intention to allow or disallow cross origin read request using Access-Control-Allow-Origin response header. For e.g. Access-Control-Allow-Origin = * (all domain allowed) or Access-Control-Allow-Origin = www.google.com (a specific domain allowed) or Access-Control-Allow-Origin = www.google.com, mail.google.com (multiple mentioned domain allowed).

Cross Origin Resource sharing standard had provided an elegant solution for cross origin resource sharing with and without controlling who can access the resource.

Web or Cross Document Messaging

It’s a new API introduced in HTML5 for cross domain plain text communication between two different domain. This new specification will ease out the way of communication between two different domain along with providing basic security.

Solution

In the beginning of this article we talked about a scenario in which we want to receive a cross domain request, but due to same origin policy restriction we were not able to do that. We can use cross domain resource sharing standard from W3C to allow these access. We need to do follow given steps to achieve the same:

1. Send Access-Control-Allow-Origin header in response

We need to setup our web or application server to add Access-Control-Allow-Origin header with proper value.
Apache Configuration to allow cross domain request from one domain www.xyz.com:
<FilesMatch ".*">
      <IfModule mod_headers.c>
        Header set Access-Control-Allow-Origin "www.xyz.com"
      </IfModule>
</FilesMatch>
Apache Configuration to allow cross domain request from two domain www.xyz.com & www.abc.com:
 <FilesMatch ".*">
      <IfModule mod_headers.c>
        Header set Access-Control-Allow-Origin "www.xyz.com www.abc.com"
      </IfModule>
</FilesMatch>
Apache Configuration to allow cross domain request from any domain:
<FilesMatch ".*">
      <IfModule mod_headers.c>
        Header set Access-Control-Allow-Origin "*"
      </IfModule>
</FilesMatch>

2. Send origin header in request

 While sending request to server we may need to send origin request header. We can achieve same by adding crossDomain attribute in Ajax request.
 $.ajax({
            url: "https://10.11.2.171:81/xxxxxx/xxxxxxx.xml",
            type: "get", 
            crossDomain: true,                                
            success: function (response) {
                alert( "Load was performed." );
            },
            error: function (xhr, status) {
                alert("error");
            }
        });

2 thoughts on “Ajax Cross Domain Resource Access Using jQuery”

Leave a Comment

Your email address will not be published. Required fields are marked *