Cross-Site Scripting (XSS) vulnerabilities are divided into three types:
- Reflected: when payload is injected from user-provided payloads, e.g. user clicks on malicious link
- Stored: when payload is stored on server-side (e.g. database) and is injected in the page content for all users
- DOM: payload is stored in client browser
DOM-based XSS works similar to reflected one - attacker manipulates client's browser environment (Document Object Model) and places payload into page content. The main difference is, that since payload is stored in browser environment, it may be not sent on server side. This way all protection mechanisms related to traffic analysis will fail.
The payload may be stored in any DOM-tree element that is used in page content. For example, if we have following URL https://vulnbank.com/vulnbank/online/history.php?test=somedata#hashpart
, these DOM-elements may be used for attack:
document.URL
: whole document URL string, e.g.https://vulnbank.com/vulnbank/online/history.php#test
document.documentURI
: same asdocument.URL
document.referrer
: previously visited page, e.g.https://vulnbank.com/vulnbank/online/portal.php
location.hash
: part of URL behind#
character, e.g.#hashpart
location.href
: same asdocument.URL
location.pathname
: URL path, e.g./vulnbank/online/history.php
location.search
: query string from URL like?test=somedata
window.name
: name of the window, e.g. if it is opened withwindow.open
function
Description
In our case, vulnerable application has the following code
$("#history-searchinfo").html(
"Searching... " + decodeURIComponent(location.hash.substr(1))
);
The request to https://vulnbank.com/vulnbank/online/history.php#<script>alert(1)</script>
will inject <script>alert(1)</script>
part to content of the page and it will be executed in the browser.
However, if we will look into the traffic, request to the server is sent without location.hash
part
Showcase
Protection
Protection against this kind of attacks should be performed on client side. The easiest way is to use DOMPurify library that suppose to sanitize payload before injecting it into the page.
It requires following steps:
- Include JavaScript-file:
<script type="text/javascript" src="src/purify.js"></script>
- Call
DOMPurify.sanitize
function before injecting it into the page
var clean = DOMPurify.sanitize(dirty);
There is also jQuery library support with jPurify project from same developers team. To use it all you have to do - include two JavaScript-files
<script type="text/javascript" src="purify.js"></script>
<script type="text/javascript" src="jpurify.js"></script>
In our demo case, it'll prevent execution JavaScript in page contents.
Reference
Links
OWASP: DOM-based XSS
OWASP: DOM-based XSS Prevention Cheat-sheet
DOMPurify Github page
jPurify Github page