Battling XSS Today …and Tomorrow (Part 1)

by | October 23rd, 2007

In annals of useless of advice, this answer from the Cross Site Scripting (XSS) FAQ on PHP Advisory, to the question of what end-users can do to protect themselves, must rank pretty high:

The easiest way to protect yourself as a user is to only follow links from the main website you wish to view. If you visit one website and it links to CNN for example, instead of clicking on it visit CNN’s main site and use its search engine to find the content.

How is a typical user supposed to take this? “Gee thanks! All I have to do to protect myself is stop using hyperlinks to get from place to place on the Web!”

Despite the tendency of commercial PCI certification programs like Hacker Safe to underplay XSS vulnerabilities, the market will surely find a way, over time, to punish sites (especially e-commerce sites) that let the burden of worrying about XSS vulnerabilities fall on the user. And this in turn means that developers will more and more be expected to make their sites XSS safe “out of the box”. With that in mind, maybe now is a good time for a review of XSS fundamentals, as well as a look ahead to how the good guys are fairing in the battle between exploits and counter-measures.

Let’s start first with the casual definition from us:

XSS is when a user runs a script (typically JavaScript) from an untrusted site in their browser’s security context. The classical example being a message board which allows the ‘bad guys’ to post a script which readers then inadvertently run when the view the posting, such ‘exploits’ often then steal the reader’s session cookie for the message board.

The problem with this definition is that it is somewhat operational and certainly not general enough to cover all the possible ways XSS may be used. However, if you get the gist of XSS from that definition the authoritative definition (circa 2002) of the issue makes a bit more sense:

The problem is two-fold:

  1. Trusting input from an external, untrusted entity, such as a user
  2. Displaying said input as output

This is bad because a malicious user could access another’s important data, such as their cookies.

That’s not a bad definition, as far as it goes. It comfortably fits the standard XSS scenarios, such as this one:

  • An attacker submits a malicious JavaScript payload to a legitimate site that accepts and displays form input from anonymous users.
  • An email containing a link to that page is sent to the victim.
  • The victim clicks on the link and goes to the compromised site.
  • On page load, the malicious JavaScript executes in the victim’s browser, reading their session cookie for the legitimate site, and sending that data to the attacker’s machine.

A more fundamental definition, which also fits this common scenario, might be something like this: XSS describes a class of unwanted HTTP side-effects that are possible because of the untyped nature of HTTP. We’ll see next week why this might be a better model of XSS going forward. In the meantime, Howard’s definition of the problem is certainly enough to get us thinking comprehensively about counter-measures, which is good. And for the particular variety of XSS exploit he highlights, a standard, easy-to-implement solution is emerging: HTTP-only cookies.

These are essentially cookies containing an extra attribute that makes them non-accessible to client-side scripting. If the malicious JavaScript that has been snuck onto an XSS-vulnerable site can’t get access to the user’s cookie, when that user unsuspectingly comes to that site, then the damage XSS can do is greatly mitigated. The main path to using XSS to hijack the user’s session or login state, for instance, is cut off. This countermeasure has server-side support in .NET and, since IE 6 SP1, client-side support in IE (details here). PHP support was slower in coming, but is available starting with version 5.2.. The add-on to make it work in Firefox can be found here. Firefox 3 will be supporting this natively which has been included since Alpha 3 (

Here’s a simple test for whether cookies can be read by client-side script. Place the following code on one of your pages so that the JavaScript can be executed. If the function below displays your browser’s cookie in the div, then that cookie can be read by any XSS payload that has been successfully uploaded to the site:

function displayCookies() {
var responseOutput = document.getElementById("responseOutput");
responseOutput.innerHTML = "Cookies accessed via Javascript: " + document.cookie;

<div id="responseOutput" class="response"></div>

How do HTTP-only cookies combat this? When setting an HTTP-only cookie, this is what it will look like to the browser, at the HTTP level:

Set-Cookie: HttpOnlyCookie=MyUserName; path=/;; HttpOnly

The last parameter in that Set-Cookie response header tells the browser to shield the cookie’s contents from client-side script. In browsers that support the HttpOnly cookie parameter, the above JavaScript test would not be able to read the cookie.

HTTP-only cookies are an important advance, in part because they are a quick-and-easy way to protect a major target of XSS attacks. That being said, it’s important to keep in mind that XSS doesn’t always rely on getting at the user’s cookie. HTTP-only cookies are useful but fundamentally reactive–they close off one way of exploiting the fact that unauthorized code has gotten onto a site and from there onto a user’s browser, but they don’t stop that code from getting where it shouldn’t be. The core problem remains one of greater control over HTTP input and output.

Next week we’ll take a look at more fundamental XSS counter-measures — and also at the next generation of XSS attacks.