Cross-Domain Ajax

<rants>

Oh, friends, friends. Whoever thought of setting up the so-called Same Origin Policy was, ahem, not very forward-looking.

A bit of history: Microsoft. Internet Explorer 5.0 (released in 1999). Outlook Web Access (OWA) team comes to Trident (IE) and asks for a way for the web page to talk to the Exchange server, asynchronously. They get the XMLHTTPRequest object, currently more famously known as XHR. Seven years later, the industry catches up and understands that XHR can be, indeed, used for Ajax.

That XHR object has a very interesting property: you can’t initiate requests to pages other than the one that the web page is originating from. For example: your site is cocktailbuilder.com, but you want to asynchronously communicate with maps.google.com through their REST API to get to something useful.

Tough luck, not gonna happen. Your XHR object has a security restriction: talk only to cocktailbuilder.com. Why? Well, because you could, theoretically, sniff the local network, then send the results to evilhacker.com.

BUT WHY IN THE WORLD DO YOU HAVE TO USE XHR FOR THAT??? Who in his right mind was setting up that restriction??? If I’m running JavaScript on your browser, I can just freaking insert an IMG tag, point it to evilhacker.com, and through clever parameters, pass any info you want.

There’s a huge hole, and they put a tiny little plug over it.

Results:

1) It’s much harder to code legitimate applications – mashups – and any kind of JavaScript-based services.

2) Security hole is as glaring as it ever was.

</rants>

OK, now to the useful stuff. There are a couple ways to set up two-way asynchronous communications across domains.

1) Outright ugly methods: Flash and iframes.

2) Proxy. You set up a service on your domain that relays all requests to the target domain. Your XHR is talking to your box, your box is being the middleman between the other box and the browser.
+ You can still use XHR and related frameworks.

– Load on your server goes up; plus, if you’re thinking about providing a service (I am – ajaxmetrics.com), this means that your clients will need to install some PHP/ASP/JSP on their server. That’s a very bad thing; this implies lots of trust between the service provider and the client (if I have my PHP code running on your server, I own your box). That’s why guys from instacomment.com are not going to make it big any time soon.

3) Script tag monkeying, also known as on-demand JavaScript. You all know that you can insert a <script> tag into your HTML, and have that tag point to an external server. But wait, you can insert that script tag dynamically! What does that mean? That you can dynamically inject JS code into your app, and that JS is coming asynchronously from the server.

Here’s the code to make that “fake Ajax” call:

function hackyAjaxCall (op, params, callbackFunctionName) {
    // Inject the script tag into the document and pass parameters 
    // through the URL. Get and execute the JS that the server .
    // returns. No, there are no security risks: the server is mine.
    var head = document.getElementsByTagName(“head”)[0];
    var script = document.createElement(‘script’);
    script.type = ‘text/javascript’;
    if (op.length < 1) {
        alert(“Error: Unspecified op parameter for the Ajax call”);
    }
    var opUrlParam = “op=” + op + “&”;
    var callbackUrlParam = callbackFunctionName ? “callback=” +
               callbackFunctionName + “&”: “”;
    var UrlParams = “p=” + escape(Object.toJSON(params));
    script.src = “http://server/endpoint.php?”+ opUrlParam +
               callbackUrlParam + UrlParams;
    head.appendChild(script);
 }

+ True, asynchronous communication between the browser and a web service on a different domain.

– This method is not as pleasant to work with as XHR, and there are no nice frameworks like Prototype, YUI, and Dojo. There was a project called “Ajax Extended”, which added things to Prototype to do this, but the website is now dead. I’d love to see this feature in core Prototype.

– Security implications: if you don’t trust the other end, don’t do this. They can inject any JS they want into your browser-side app, and steal your cookies.

Further reading:

1) XML.com article of both mechanisms mentioned above.
2) Good article on the subject from snook.ca.

Cheers!
-cb

Cocktail Builder: JavaScript Alcoholic