Ajax Cross Domain Resource Access Using jQuery

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 pages:

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

In our case, we were accessing XML as an Ajax request resource. I was curious to check if the non-XML cross-domain resource was successfully loading or not. But finally, I realized that it is not going through. jersey-spring-boot-quick-starter-guide

In our Ajax call, requesting domain was not the same as the 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");
}
});

Sometimes it’s mandatory to have a cross-domain request, consider the case of web components in a desktop application (file: URIs) or others.

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

Same Origin Policy

The same-origin policy restricts access to other domain DOM or other resources due to security concerns (talked further in the article). It had been implemented by all of the modern (with bit flexibility in one to more security in others) browsers to draw a boundary for scripting languages and mechanisms like DOM manipulation and AJAX request.

An origin is decided by the schema, host, and port of an URL. Let’s say we have a web page with a 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 URLs from this page, we will see, URL is following the Same-origin policy or not.

URL Description Same Origin Policy
Chrome Firefox IE
https://www.devhours.com/dir1/nice2.html Same Schema & host Y Y Y
https://www.devhours.com/dir2/nice1.html Same Schema & host Y Y Y
https://username:[email protected]/dir2/nice1.html Same Schema & host Y Y Y
https://www.devhours.com/dir2/nice1.html Different Schema N N N
https://www.devhours.com:82/dir2/nice1.html Different Port N N Y
https://devhours.com/dir2/nice1.html Different host N N N
https://www2.devhours.com/dir2/nice1.html Different host N N N
https://v2.www.devhours.com/dir2/nice1.html Different host N N N

IE doesn’t consider different ports on the same domain and protocol as cross-domain requests.

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

Cross-Origin Network Access

When we talk about cross-domain access failure using Ajax, the first thing came to our mind is, why it’s 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 the web app world, the same-origin policy seems to be restrictive sometimes, especially if certain domain deliberately wanted to allow cross-domain access or same app have interdependent resources on several domains. There are a couple of standards or techniques which came in handy for solving the Same Origin Policy-based restrictions. Let’s have a look at 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 domains. This new specification will ease out the way of communication between two different domains along with providing basic security.

Solution

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

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

We need to set up our web or application server to add the Access-Control-Allow-Origin header with the 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 requests from any domain:

<FilesMatch ".*">
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
</FilesMatch>

2. Send origin header in the request

While sending requests to servers we may need to send an origin request header. We can achieve the 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");
}
});

Sources:

  1. https://en.wikipedia.org/wiki/Same-origin_policy 2.
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript
  3. https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs
  4. https://www.w3.org/Security/wiki/Same_Origin_Policy
  5. https://blogs.msdn.com/b/ieinternals/archive/2009/08/28/explaining-same-origin-policy-part-1-deny-read.aspx

Leave a Comment

Your email address will not be published.