Cross-Domain Ajax

Published in PHP Architect on 16 Oct 2006

Welcome to another edition of Security Corner. This month’s topic is cross-domain Ajax, and it’s specifically an introduction to a few of the security concerns that I hope to elaborate on in future editions. If you don’t use Ajax, don’t know what it is, or just believe it’s nothing more than the latest trend, you might think this topic is irrelevant to you. On the contrary, this is a common misconception that I hope to address. With a rich collection of client-side features supported by most modern browsers, attacks that target your users are becoming much more sophisticated, and as a web developer, you should be prepared.

Before I begin, I have a confession to make. I’m not an Ajax expert. I’m not even a JavaScript expert. Hopefully, these facts can help you begin to appreciate that this month’s topic is relevant to all developers, even those who don’t develop in JavaScript or use Ajax themselves.

What Is Ajax?

Ajax describes a collection of technologies that let clients communicate with a server without a page load. On the surface, this sounds like nothing new. What sets Ajax apart from traditional client-side technologies is the ability to both send and receive HTTP. This gives client-side scripts the ability to provide much richer user interfaces, but it also gives attackers another tool to use in exploits as well as some new potential targets.

The primary enabling technology is XMLHttpRequest(), typically abbreviated as XHR, an API that lets you send and receive HTTP requests and responses. The security policy for XHR is similar to other JavaScript features, and the restriction that many Ajax developers have encountered in particular is the same-origin policy. This prevents XHR requests initiated on a page at one domain from sending requests to a page on another. This is an important policy, and before continuing, I’d like to briefly explain why.

Cross-Site Request Forgeries

Cross-site request forgeries (CSRF) can be described as any technique that causes an innocent victim to send an attacker’s request. In order to be sure that a user’s request is intentional, most developers use a one-time token (sometimes called a shared secret or CSRF token):

  1. <?php
  2.  
  3. $token = md5(uniqid(rand(), TRUE));
  4. $_SESSION['token'] = $token;
  5. $_SESSION['token_time'] = time();
  6.  
  7. ?>
  8.  
  9. <form action="buy.php" method="POST">
  10. <input type="hidden" name="token" value="<?php echo $token; ?>" />
  11.  
  12. <!-- … -->
  13.  
  14. </form>

This gives the developer something to check before taking an action.

By using this technique, it’s very difficult for an attacker to forge a request from a victim, because in order for the request to be successful, the attacker must first obtain the victim’s token. By visiting the page and viewing source, the attacker can only obtain the attacker’s own token, not the victim’s. However, if the attacker can provide JavaScript that the victim’s browser executes, that JavaScript can visit the page and obtain the victim’s token, successfully bypassing the CSRF safeguard.

Because of the same-origin policy, a victim who visits the attacker’s website (or any other website with malicious content) is somewhat protected against this, because any JavaScript executed within that context cannot make requests to other domains. However, hopefully you can already imagine the dangers present in the following situations:

  1. The target web site has a cross-site scripting (XSS) vulnerability, allowing an attacker to embed the malicious JavaScript within the same domain.
  2. The same-origin policy does not apply to XHR.

Luckily, the same-origin policy does apply to XHR, so your only concern as a PHP developer is the presence of any XSS vulnerabilities in your applications. With the rise in popularity of Ajax, XSS vulnerabilities are more dangerous than ever.

The risk that XSS vulnerabilities present can perhaps be made clearer by considering JavaScript a potential parasite, a tool of the attacker that is executing from within a client’s (victim’s) context, able to send and receive HTTP requests and responses as if it were that client. In essence, an attacker can impersonate another user without needing to hijack that user’s session.

Cross-Domain Ajax

There are quite a few creative techniques being used to work around the same-origin policy, and I’m only going to discuss a few this month:

The idea behind an application proxy is to have XHR send requests to a URL within the current domain, and a server-side script proxies that request to another domain. This is simple and effective, and it erases the primary security concerns, because the browser (or a rogue script) cannot make direct requests to the other domain.

With on-demand JavaScript, developers use the src attribute of the script tag to identify a remote URL. This has always been possible, and in order to make this work, the response needs to be valid JavaScript. The reason this does not present a major security concern is that the response cannot be examined. Therefore, an attacker cannot use this technique to obtain one-time tokens (shared secrets) of other users, even though the response may potentially contain such information.

The last technique, using an IFrame proxy, is a bit more complicated to explain. It’s a clever hack, but because I promised not to veer off-topic, I’ll point you to a URL where you can learn more:

http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book75

Although this technique does get around the same-origin policy, the inherent risk is mitigated, because it requires cooperation. An attacker cannot use this technique to exploit a site that doesn’t support it.

The documentation stresses the risks involved in implementing this technique on your own site:

You should not experiment with this technique unless you are very restrictive on the clients and API URLs that are allowed. Placing the Server document on your web server means opening up the allowed URLs to the world.

It might not seem important to consider the security implications of Ajax (and particularly cross-domain Ajax), but it is under either of the following two conditions:

  1. You enable cross-domain Ajax using a technique such as the IFrame proxy, where you allow cross-domain Ajax requests initiated from other domains.
  2. Your users have browsers that support Ajax technologies.

Because the second condition is true for almost all of us, cross-domain Ajax is a topic worthy of our attention.

Until Next Time…

The impact of Ajax and other emerging technologies and development methodologies is an interesting and evolving subject among web app security experts. Ajax has already enabled a few major exploits, because the target site was either vulnerable to XSS or allowed cross-domain Ajax requests.

The most important point I hope I have made is that you don’t have to use a technology in your own app in order for it to be relevant to you. Every new technology can be a potential tool used by attackers to develop new exploits, whether exploiting old vulnerabilities in new ways or creating brand new exploits.

I hope to continue this topic by describing some of my current research that has revealed a major security vulnerability in a popular Web 2.0 application.

Until next month, be safe.