What is DOM-based XSS?
The Document Object Model (DOM) lets web developers dictate through HTML source code how a user’s web browser should display a web page. DOM-based XSS attacks seek to exploit the DOM in a simple two step process:
- Create a Source: Inject a malicious script into a property found to be suceptible to DOM-based XSS attacks. Common injection vectors include document.url, document.location, and document.referrer objects.
For a typical example of how a DOM-based XSS attack is executed, it’s suggested that you read DOM XSS: An Explanationof DOM-based Cross-Site Scripting.
DOM-based Cross-site Scripting
DOM-based Cross-site Scripting (from now on called DOM XSS) is a very particular variant of the Cross-site Scripting family and in web application development is generally considered the amalgamation of the following:
- The Document Object Model (DOM) – Acting as a standard way to represent HTML objects (i.e. <div></div>) in a hierarchical manner.
- Cross-site Scripting (XSS) – A specific Web Application vulnerability.
To build some part of the page, without sanitizing the return value. That said, the purpose of this article isn’t to explain DOM XSS fully, but rather how to defend against it.
On one of our Test HTML5 applications there is a DOM XSS vulnerability that can be exploited via the following payload:
Which would look something like the following image – an informational message with a simple alert. Note how the payload is stored in the GET request, making it suitable for Social Engineering attacks.
The above is quite trivial but is an easy way to prove our point. The payload is embedded in the URI and so can be easily made part of a phishing campaign. The payload can be manipulated to deface the target application using prompt stating, “Your session has expired. Please insert your password to refresh your session”. A simple yet effective way to harvest passwords.
If we dig deeper, we find out that the #redir route is being executed by another file, called redir.html found here. If you view the source of the page, the gist of the code is as follows:
<script> var redirUrl = decodeURIComponent(window.location.hash.slice(window.location.hash.indexOf("?url=")+5)); if (redirUrl) window.location = redirUrl; </script>
Essentially we are exploiting the window.location.hash source which is evaluated in an HTML Element Sink.
Detecting DOM XSS is difficult using purely server-side detection (i.e. HTTP requests), which is why providers like Acunetix leverages DeepScan to do it. These payloads are never sent to the server due to being behind an HTML fragment (everything behind the # symbol).
If you have to use user-input at any point in time on your page, always use it in the context of literal “text” and never as potential code. Avoid methods such as:
And instead use safer functions when using user input like so:
This will treat the previous payload we showed as just text and nothing else. Additionally, avoid using user input entirely especially ones that can affect:
The above three properties may manipulate the DOM thus leading to such vulnerabilities. Keep in mind that DOM XSS and XSS are not mutually exclusive, meaning that your application can most definitely be vulnerable to both XSS and DOM XSS—even though XSS is normally found in dynamic pages and DOM XSS in static ones. The good news is that if user input is handled properly as a foundational level (e.g. your framework), then you should be able to mitigate all XSS-based vulnerabilities.
For a great cheat sheet on how to prevent DOM XSS entirely, I would highly recommend going over the OWASP DOM based XSS Prevention Cheat Sheet.
Lastly, leveraging a Web Application Scanner such as DeepScan by Acunetix will greatly increase both the speed and accuracy to which developers and security professionals can detect vulnerabilities like DOM XSS and fix them and thousands more.