Problem Statement

If you are developing a web application and trying to load a data from other domain then a browser will not allow this request and raises an error saying 

XMLHttpRequest cannot load http://SomeOtherDomain/dataservice. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://MyLocalDomain’ is therefore not allowed access.

The above message is self-explanatory and the reason for this error message is that almost 96% of recent browsers follow Same-Origin-Policy security policy. As per this policy, no browser will allow any requests to access data on other domain sites i.e., for example, if a browser is running a.com site and this site trying to access some data on b.com is not allowed. This policy is strictly followed by every browser because of many security issues of accessing one application data by other application without knowing to the user. 

$.getJSON( 
  "http://b.com/employees/data.json", 
  function(jsonobj) { console.log(jsonobj); } 
);

But, Browser will allow loading images and scripts from other domain and executes, for example, CDN’s from where we use to load famous scripts like jQuery

Possible Solutions

To overcome this limitation we have a couple of workarounds and following are those 

Using Proxy Implementation 

This is a common workaround as if the browser is not supported to access any data on a different domain. The application should request to its own web server and in turn, this Web server is allowed to request to other domain and access required data and returns back to the requested browser.

With this approach, there will be a heavy load on the web server and leads to some other performance problems and not able to utilize the powerful browser capabilities.

Below is the server logic to call a page on other domain server and access data using .NET technology.

static async Task<Employee> GetEmployeeAsync(string path) 
        { 
        static HttpClient client = new HttpClient(); 
            Employee emp = null; 
            HttpResponseMessage response = await client.GetAsync(path); 
            if (response.IsSuccessStatusCode) 
            { 
                emp = await response.Content.ReadAsAsync<Employee>(); 
            } 
            return emp; 
        }
 Using JSONP 

JSONP (JSON with “Padding”) is a technique by using this we can overcome the heavy requests issue on a Web server and this technique breach the browser level security policy i.e., Same-origin-Policy.  This is possible by calling the other server getting the data and surrounded this data with a given function name (i.e., padding around loaded data) such that browser will treat this as a local function with this data as an input parameter.  i.e., while requesting the cross-domain page we need to provide call-back function name. When browser finds this call-back parameter, it understands it as JSONP request and it will pad the output from the page with the given callback function. 

Note:

  • This function should be implemented before padding to the loaded data.
  • JSONP can be used only for GET requests.

Let’s understand more how this works. This technique can be implemented with Ajax calls and also without Ajax Calls.

Implementing Without Ajax 

Generally, most developers not aware that JSONP request can even do without any Ajax request with my experience. I thought to discuss this implementation technique here.

Below is the implementation logic

<html> 
<head> 
  <title>TechXposer JSONP Without AJAX Demo</title> 
  <script type="text/javascript"> 
window.onload = function(){     
  
var dynNumber = Math.round(1000 * Math.random()); 
    var jsonpCallbackFnName = "cb_" + dynNumber; 
     
    window[jsonpCallbackFnName] = function(responseData){ 
        console.log(responseData); 
    } 
  
    var scriptTag = document.createElement("script"); 
    scriptTag.src = "http://b.com/dataservice?callback=" + jsonpCallbackFnName; 
     
    document.body.appenChild(scriptTag); 
} 
  </script> 
</head> 
</html>

Let’s discuss the above code. As observed we are implementing the complete logic on body load why because we are using a document object and this object won’t be created before loading the body content. Here our target is to build the <Script>tag with the cross-domain page as a source and appending a callback function name using callback parameter as a query string. For this, We are trying to generate a unique call-back function name because to overcome the browser cache. Here once we have the unique method name, we are trying to dynamically implement this function using Window object such that once browser gets the data and padded with given unique function name it will call that method and before this call this function should be available.

When we run the above HTML it will generate following script tag

<script type="text/javacript" src="http://b.com/dataservice?callback=sb_1234"></script>

And function will be  

function sb_1234(responseData){ 
console.log(responseData); 
}

A browser will prepare the call as follows by padding function name sb_1234 and this is a local call so the browser is still following Same-Origin-Policy. 

sb_1234({<data from cross domain>});
 Implementing With Ajax 

As we aware AJAX provides more flexible API. The same above example using AJAX call as follows. 

 $.ajax({ 
  url: "http://b.com/dataservice", 
  dataType: "jsonp", 
  jsonpCallback:  jsonpCallbackFnName 
});

Even, this AJAX request can be done in a single line using its awesome enrich API as follows  

$.getJSON("http://b.com/dataservice?callback=" + jsonpCallbackFnName,function(responseData){ 
  console.log(responseData); 
});

Security Issues using JSONP

  1. Need Trust on other Domain: The source domain should have complete trust on cross-domain before sending JSONP request. Because if the other domain is not trusted and any 3rd party it could be a security issue. The other site can inject any script which leads to complete system on risk.
  2. CSRF Tokens: As JSONP only allowed for GET requests, if you are allowing any JSONP requests to access your data please make sure to accept even CSRF Token as in general practise this token will be used mostly for POST request but to make sure you are getting request from proper Origin it will be good practise to expect a CSRF Token to avoid Cross-Site Request Forgery vulnerabilities.

To get rid of all these Security Issues, later CORS has been introduced. Will discuss CORS more in my next article.

Happy Coding 🙂