On: DOM based XSS injection. The workings and the protection

Categories Security

Most endeavors people undertake are subject to the 80/20 principle, sometimes referred to as “the vital few and the trivial many”. Web application security may be said to also be subject to it – most of the attacks can be dodged by hiding the error messages and infrastructure information, getting the auth and session management right, following secure development practice cheat-sheets that abound on the internet – the vital few. Having a Web Application Firewall (WAF) in front of your backend web server and a DDoS provider on the side brings you almost to the home stretch… Almost, but not quite. A vulnerability that is immune to conventional WAF detection and prevention mechanisms exists and can be encountered on the internet – DOM based Cross Site Scripting (XSS), leveraging the URL anchor a.k.a fragment identifier (#). As it’s happening solely on the client side it is not visible to the conventional WAF deployments (inline, proxy). In this sense it is the “hidden”, the “sometimes forgotten”, it is part of those “20%”, that has the potential to bring you “80%” of your problems [1].


An example:

Anchor identifier is used to scroll an HTML page to a particular place of interest. A fact known, let’s say, from intermediate home users all the way up to seasoned security specialists. What is commonly forgotten is that the fragment identifier is never sent to the backend with the HTTP request. and that the danger starts when that innocent looking identifier is used by the developers in their the javascript code, in various ways.

The RFC specifies: “The fragment identifier consists of additional reference information to be interpreted by the user agent after the retrieval action has been successfully completed” [2].

Let’s illustrate the processing of the response with the fragment identifier when Javascript is used, as is the case with DOM based XSS:

Let’s say the following javascript snippet was used in a production web application:

jQuery(function () {
  var h = window.location.hash;
  if (h) jQuery("a[href*=" + h + "]").click()
}); // works on old versions of jQuery

This code simply takes the window.location.hash (i.e. the string that is in the URL for the current request) and places it into the href attribute of the anchor tag and then performs an action on it (let’s say clicking it). Experienced reader might notice that this is a glaring open redirection vulnerability, however, there is also a DOM based XSS vulnerability. A string #<img/src/onerror=alert(1)> passed in the URL was causing the alert message to appear indicating a successful injected javascript execution, proving the existence of attack vector. How can a developer or security provider deal with this issue?

A security provider has two primary purposes – attack mitigation and attack prevention. The second one is supported by analysis of the web application (logic, architecture) and the traffic patterns the web application is associated with (log data, monitoring). Considering that the payload never reaches the application or the intermediate WAF, where it could be blocked or detected, we can formulate the question – how can we protect the web application?

Three situations can be defined where different actions will need to be taken: normal SDLC (i) and immediate prevention / patching (ii) and long-term prevention (iii). An exhaustive list of DOM XSS prevention techniques during (i) would prolong the discussion and the value to the reader would only arise from having a summary of those methods in one place. The standard practices ranging from web application vulnerability scanning, taint tracking to secure front-end coding practices can be mentioned.


Immediate prevention / patching:

If changing the offending code is not an option, response body rewriting is a very beneficial technique for these types of vulnerabilities. And the HTTP server or intermediate proxy can (as is the case with WAF) is rewriting the response body, changing the javascript code to a non-vulnerable, functionally equivalent one. In terms of our previous example the solution looks as follows:

jQuery(function () {
  var h = window.location.hash;
  if (h) jQuery(‘body’).find("a[href*=" + h + "]").click()
}); // works on old versions of jQuery

Below is a summary of methods on how to rewrite response bodies with common HTTP servers:

Server Module Implementation / hint
Nginx ngx_http_sub_module http://p.defau.lt/?Ekh_YUu7UsD2bJyIHf3trQ
Nginx Nginx + lua. LUA body_filter http://p.defau.lt/?guwy4TEV_6K2eVA6cdfqrg
Apache Apache Module mod_substitute http://p.defau.lt/?1596jP6yqkkSuzhGGIv_hg
Apache As of version 2.3 LUA can be used as a scripting language for Apache. Response body rewriting is possible there as well. http://p.defau.lt/?_bbUHAb0ZRBFrWmsb0NTdQ
Varnish Possible, but hacky: https://github.com/aivarsk/libvmod-rewrite
HAproxy Not possible. Might be possible with LUA in the future


Long term prevention:

There is another technique that can be employed to both detect, log and prevent the attack from executing to it’s completion – Javascript injection to the web application. Javascript processing has a defined sequence of steps – the page load cycle and event cycle. When the page is loaded the downloaded HTML is parsed into a DOM tree – an in memory representation of the HTML. DOM parsing is sequential and the scripts are executed in the sequence they are found. As mentioned in the illustration, the fragment identifier is available right from the beginning which means we can inspect it with the Javascript injected right below the <head> tag:

&lt;script type="text/javascript"&gt;
  if window.location.hash {
    var re = new RegExp("onerror\(");
    if (re.test(window.location.hash)) {
      alert("Message to the user...”);
      window.stop(); // stop DOM parsing and execution
    } // inner if
  } // outer if

It is left for the interested reader to If you’ve made it this far think about possible extension of this simple script for logging the activity and more advanced detection for multiple types of payloads.

This vulnerability is an interesting one for us, because it highlights the fact that Web Application Firewalls will not necessarily see all vulnerabilities for a given web application. As always, we need to remain diligent when writing and protecting code against these types of hidden dangers!


Footnotes and resources:

  1. The 20% is not just contrived to illustrate the 80/20 principle. Although content Injection vulnerabilities are not a category that is usually recognized in the statistical reports, XSS and Content spoofing vulnerabilities have a likelihood of ~60 percent for any randomly selected web app on the internet. See: https://goo.gl/7epzGp
  2. https://tools.ietf.org/html/rfc5147#page-4

Leave a Reply