14/03/2014

Second Line of Defense in Web Applications Part 2 XSS Filter

Most modern browsers implement a very basic XSS filter as additional defense. Such an XSS filter was first implemented in Chrome/WebKit and is called “XSSAuditor”. Microsofts Internet Explorer since version 8 also provides such a filter. Unfortunately Firefox doesn’t ship with an XSS filter, but the excellent NoScript add-on provides an XSS filter besides many other client side mitigation techniques. These XSS filters detect JavaScript <script></script> tags inside the HTTP parameters and if the tags end up in the HTML document, the browser will prevent the execution of the JavaScript.

This already shows a conceptual limitation of the browser based XSS filter: They cannot detect stored XSS vulnerabilities. That is if the XSS payload isn’t anywhere in the HTTP parameter but is stored in the web application. A browser can of course not differentiate between legitimate <script> tags and malicious ones because they look just the same. But for reflected XSS vulnerabilities, which are probably more common, this approach works just fine.

How XSS filters handle detected XSS payloads differs from browser to browser. For example the IE8 filter tries to sanitize the payload, so the site can still be viewed in case the detection was a false positive. A good example for a false positive was the Google search for “what’s<script>”, which looks like “http://www.google.com/search?hl=en&q=what’s%3Cscript%3E” in it’s simplest  form. Of course the search query is echoed back to the user and looks like an XSS attempt to an naive filter and removing the script tags might break the web site.

Trying to sanitize the detected XSS payload modifies the site in a way the developer did not expect and might break more things. The IE8 XSS filter has also become famous because in some cases it created XSS vulnerabilities, where there were actually no XSS vulnerabilities. *

Chromes XSSAuditor goes another way. Instead of trying to sanitize the string, it leaves the script tags inside the DOM, but does not execute the JavaScript inside the tags. This might also break the website because legitimate JavaScript might not be executed but is less error-prone than the IE8 variant, because it does not actively modify the document.
But also the Chrome filter is not perfect. It has been demonstrated * that it is easy to bypass the filter if two consecutive HTTP parameters are used to deliver the XSS payload. For example the first parameter could be

<script>alert(document.cookie); void('

and the second one contains

');</script>

Once the document is rendered this will result in a valid JavaScript and will be executed.

<script>alert(document.cookie); void('<some>html</some>');</script>

 

Firefox currently contains no XSS filter, but add-on NoScript also provides a XSS filter. It works similar to the filters of the other browsers. Because it is an add-on it is not as tightly integrated and does not have all the possiblities the other filters have. * *

It works by sanitizing the HTTP parameters before the request is sent and therefore the payload can never reach the server or the browsers DOM. Because the DOM is not directly modified it does not suffer the same problems as IE8, but because of the sanitization legitimate requests might not be what the user expected. It is nevertheless a very good idea to use the NoScript add-on even when the JavaScript blocking functionality is not used, since it offers some good additional protection. It is actively maintained and false positives and bypasses for the XSS filter are promptly patched.

The XSS filters can be controlled by web applications through an HTTP header:
“X-XSS-Protection” (or with the “X-” prefix omitted depending on the browser).
There are three modes which can be requested by the web applications

  •  “X-XSS-Protection: 0”
    Disables the XSS filter. This can be used when the XSS filter detects a false positive and breaks the site
  • “X-XSS-Protection: 1”
    Enables the XSS filter, which is default.
  • “X-XSS-Protection:1; mode=block”
    Enables strict blocking mode. This instructs the browser not to render the site if the XSS filter detected something. This should be set by modern web applications and it should be tested if the filter detect any false positives in the web applications because those will now result in a blank page.