Cross-Domain Requests, State of the Browsers

Published on 08 February 2011

Client-side mashups are great: the response gets faster if it doesn’t have to go through one more machine, and user security and privacy can be improved by having the client directly fetch his own data, without having to grant access to a tihrd party web server.

But the web browsers can’t just let web pages do XMLHttpRequest calls to different domains: that would open security holes. They explicitly forbid pages from requesting a resource from a different domain, forcing the web developers to tunnel request through their server or use a trick such as JSONP.

Luckily, browser vendors and the w3c are preparing a standard for access control letting developers do cross-domain requests in a controlled way.

This will be important for the following so note that there are 3 parties involved in a cross-domain request: <ol> <li>The user</li> <li>The consumer page</li> <li>The producer page</li> </ol> <h2>The problem with cross-site scripting</h2> The reason why web browser don’t allow cross-site scripting by default is that it could be used to steal users’ information. The scenario is the following : <ul> <li>User visits a malicious page</li> <li>The page pulls user’s information from a different website, for example the email feed from the webmail (works because the user is authenticated)</li> <li>Data is sent to the malicious server through another XMLHttpRequest (not cross-domain this time) and user data is stolen</li> </ul> Cross-domain requests is a real security issue, which is why browser couldn’t just open the gates. <h2>A imperfect workaround: JSONP</h2>

JSONP is a usage pattern to do cross-site requests. It uses the fact that you can include external JS using script tags. So while you are not doing an XMLHttpRequest, it lets you achieve similar functionalities.

See for example how it works for Twitter:

<script src="http://twitter.com/status/user_timeline/erwan.json?count=10&callback=onResponse"></script>

With the code above, my local function onResponse will be called with the result in parameter. So the Javascript is not your usual static file, but is a response to a query.

jQuery and other libraries can even manage that for you, so the jsonp call looks like a regular XHR call. It will define the function and insert a script tag to your page so you just write a “$.ajax” call.

The biggest issue with this approach is that it moves the security hole from the provider to the consumer. When you use this in your pages, you have to trust the provider to serve the Javascript it is supposed to serve. Nothing prevents the provider to do XMLHttpRequests to your domain then send them back to their server for example by using an image tag.

W3C Standard: CORS

The W3C provides a standard way to authorize “Cross-Origin Resource Sharing”. This is implemented in recent versions of Chrome, and Firefox since version 3.5.

In short, the provider can add headers to explicitly allow cross-domain calls either to some domains or everyone. Mozilla has a good documentation on HTTP access control.

This works well for public pages, that don’t require the user to be logged in. For page that do require login, more work is needed:

  • The provider needs to add a header explicitly allowing requests with cookies</li>
  • The consumer needs to set a credentials flag to its XHR asking for cookies to be sent

with IE

First, the good news: IE provides access control to do cross-domain requests. Now the bad news: as usual, IE can’t do like the others and they have their own non-standard way to provide it.

Instead of a regular XMLHttpRequest, you need to do a XDomainRequest! Moreover, it works only for public pages, not for authenticated pages. So if you need to send he cookies and you want your application to work in IE, you’re pretty much screwed.

Conclusion

Doing a cross-request using standard ways is still a pain. It’s especially a pain because libraries like jQuery don’t do anything to help you: they don’t use an XDomainRequest on IE when it’s needed, so you’ll have to do the switch manually.

JSONP will probably still be useful for a while. If you want to pull public information that is not available in JSONP, here is a trick: use YQL. It can transform any source (feed, rest api call, HTML page…) into JSONP. That way you can get any data to your page in pure Javascript.

TAGS: ajax  browsers  cors  http  tech