Ajax Security: A Server-Side Solution?

Posted: March 15th, 2007
Filed under: Uncategorized

There has been a lot of discussion lately in the Ajax community about the security implications of using raw JavaScript or JSON as a response in an Ajax application (see http://robubu.com/?p=25, http://ajaxian.com/archives/the-safety-of-json, and http://ajaxian.com/archives/securing-your-json).  The primary concern is that, in some instances, third party sites can gain access to private data in this format using a technique called Cross Site Request Forgery (CSRF — http://en.wikipedia.org/wiki/Cross-site_request_forgery).

CSRF is not a new idea, nor is it unique to Ajax, but let’s briefly summarize how the technique may be used within an Ajax application.  Say that a user logs into their private site and authenticates, which issues a cookie allowing them to fetch content from various protected URLs. Later, the user visits an unknowingly evil site.  This evil site uses JavaScript to include a file from your private site by inserting a <SCRIPT> tag referencing assets in JavaScript format of interest. Because it is running on the client and you are still authenticated against your private site, it has no problem getting to the URL of interest since the access cookie will be sent with the rogue request. Once the evil site page has received the data of interest, it then makes a silent request back to itself, typically using an XMLHttpRequest (XHR) object, and passes the stolen data – mischief accomplished, victory for the evil site! Booooo. Hiss.

Now, given this high level overview, let’s look at this approach a bit more deeply. First, we note that the evil JavaScript must make use of the <SCRIPT> tag to steal the data. Why did they not use the XHR object to steal things? Well, as even neophyte, Ajax programmers know the XHR object must obey the same origin policy — meaning that it cannot access resources on domains other from that which it is served.

It should be noted that there are limitations to what can be stolen easily via the <SCRIPT> tag because any data that is included this way must be something that will run on its own when evaluated by the browser’s JavaScript interpreter. For example, if the requested URL on the secured site returns:

var credentials = {“username”:”testpassword”, “password”:”testpassword”};

then the evil script can easily parse credentials and send the relevant data wherever it wants. In addition, if the file returns

processCredentials({“username”:”testpassword”, “password”:”testpassword”};

then the evil script can create a function called “processCredentials” and again easily have access to the data.

Given that the response must be executable, it has been suggested that if a site returns JSON instead of script like so:

{“username”:”testpassword”, “password”:”testpassword”}

it will then be safe because nothing can be done when the response is evaluated. However, Joe Walker offers a dispute to this and suggests how one might still access the data in this scenario (http://getahead.org/blog/joe/2007/03/05/json_is_not_as_safe_as_people_think_it_is.html).

So, how to really solve this problem, and why does Port80 Software think a server product like LinkDeny has anything to do with Ajax security issues? (Yes, we had to go there.) Well, it turns out that the problem the Ajax folks are encountering is, at its heart, a broad-based one — access limitation without authentication. The initial aims of LinkDeny were to stop image lechers and provide Web administrators finer grain access control to various objects on their Microsoft IIS Web server(s). The Ajax security problem we just described is fundamentally that the evil site should not be able to access the file that produces the JavaScript response or even any JavaScript resource directly. The bad guys should be blocked because they are not accessing the resource from an allowed URL. This idea is no different than a user not being allowed to directly hotlink to an image or other object on your server in an attempt to steal your bandwidth or content…

The primary mechanism to thwart direct access to objects including scripts on a server is to check the HTTP Referer header. Basically, in order to be allowed to fetch certain objects, a valid Referer header must be sent that is the same as the serving domain. With such a restriction in place on the secured server, the page on evilsite.com would have to forge the header in order to conduct the nasty CSRF attack. Using JavaScript without XHRs, this header is not possible to modify — and thus the bad guys are foiled.

Now, even if you could somehow spoof this header (as our image leeching friends do occasionally), there are plenty of other countermeasures that you can deploy. You can issue special time-sensitive access cookies or have short-time unique URLs that must be used for the requested objects. Such measures make it much more difficult for the evil site to lay a trap that is active long enough to get what they want…

So, to help plug this script-related security hole at the server level, don’t let any domain link to objects such as .js files or URLs that generate JSON or JavaScript unless it is your own domain or one that is explicitly allowed. This is easily accomplished using Referer header checking (and other access control techniques with teeth) either with a product like LinkDeny for IIS or mod_rewrite for Apache.

Port80 Ajaxians

No Comments »

Comments are closed.