The key to centralized AJAX services

The Problem: Same Origin

While working on a top secret project at We-Create, I was faced with a road block regularily encountered by many web developers: the ‘Same Origin’ security policy. Simply put, it’s the security restrictions in the web browser that confines actions to the same domain where the page is located. For example, in accordance with the policy, JavaScript running on this page in Jeffreysambells.com should only communicate with JeffreySambells.com and be denied access to any other domains. Usually this isn’t a problem as the policy doesn’t apply to loading non dynamic objects such as images from other domains, and most AJAX requests will be between the browser and JeffreySambells.com. As well, to protect against Cross Site Scripting (XSS), it makes sense to disallow seemingly random requests to other domains. The problem arises in places such as my top secret project where I require a centralized data service on one domain which communicated via AJAX with pages viewed on other domains. With the ‘Same Origin’ security policy this isn’t possible using any traditional AJAX methods! But it is possible with a little JavaScript trickery. The most common AJAX methods use the XmlHttpRequest object or the Microsoft equivalent ActiveX object to make requests. If you try to pass in a full URL to another domain, both will error, denying access to your request. Similarly, some people have been crafty and attempted to use an embedded <iframe> window to retrieve their data from another server. This can be somewhat successful as you can load an external domain using the iframe and pass in any GET parameters you like, but you can only submit data this way, not retrieve it.

The Solution: XssHttpRequest

To overcome the Same Origin policy, I had to revert back to an ‘old-school’ way of doing AJAX and create an XssHttpRequest JavaScript object that dynamically inserts <script> tags to load external JavaScript. This works because the script tag’s src attribute isn’t bound by the Same Origin policy. We’ve all used it to load javascript from thrid party sources such as the Google Maps API and similarily that’s what we’re doing, only dynamically.

Advantages of using XssHttpRequest

  • Allows Cross Domain AJAX
  • Compatible with most popular browsers
  • Implemented object can use similar methods to standard AJAX objects

Disadvantages of using XssHttpRequest

  • You need to control the response end or create a server side tunnel using cURL or WGet
  • Can only load valid JavaScript
  • You can only request using GET, not POST

Get the XssHttpRequest source now

To overcome the disadvantages listed above, the XssHttpRequest object sends a variable name with it’s request. The responding script then only needs to return a JavaScript source file that defines the supplied variable. The flow is illustrated in the following diagram: XssHttpRequest Flow Diagram

A Working Example

To see it work for yourself, I’ve setup a simple test script here on JeffreySambells.com. The following PHP script is hosted here at http://JeffreySambells.com/code/XssHttpRequest/response.php:

<?
$script = <<<JAVASCRIPT
	alert('Hello World from {$_SERVER['SERVER_NAME']}');
JAVASCRIPT;
echo 'var '.$_GET['XssHttpRequestVar'].' = "'.addslashes($script).'" ;';
?>

Download the source for the XssHttpRequest object and use it the same way you would the XmlHttpRequest object:

<script type="text/javascript">

//include source for XssHttpRequest from link above

function doRequest() {
	request = new XssHttpRequest();
	request.open("GET", "http://jeffreysambells.com/code/XssHttpRequest/response.php", true);
	request.onreadystatechange=function() {
		if(request.readyState==4) {
			alert('Completed request: ' + request.responseText);
			eval(request.responseText); //execute the javascript.
		}
	}
	request.send(null);
}

window.onload=doRequest;

</script>

Now, when the page loads you should see a JavaScript alert of the responseText and a second alert that says ‘Hello World from JeffreySambells.com’. In the above example I’ve eval()’d the responseText to do this, but you could easily return and XML file and then parse the XML as nesessary! Just remember that the respons needs to be valid JavaScript, but the JavaScript can define whatever you want.

The example illustrated here is simple but it proves data from JeffreySambells.info was loaded into your web page. Loading data from another domain is the key to a centralized AJAX service so start building your centralized services now! Feel free to use and modify the XssHttpRequest object to suit your needs, I only ask that you let me know of any improvments so that I may improve the script here and let me know if you use it in a project so I can link back to your project as an example.