Cross-Site Scripting (XSS)

What is cross-site scripting?

At a Glance:

Cross-site scripting (XSS) is a code injection security attack which delivers malicious, client-side scripts to a user’s web browser for execution. Targets are not attacked directly, rather vulnerable websites and web applications are used to carry out cross-site scripting attacks when users interact with these sites/applications.

An unsuspecting user will, for example, visit a compromised website, at which point the attacker’s malicious script is loaded and executed by the user’s browser. This can lead to exfiltration/theft of sensitive data, session hijacking, and much more. Because of its wide support across many web browsers and platforms, JavaScript has been a popular choice for XSS attack authors, but an attack can be crafted with any language that is supported by browsers. While XSS attacks have been around for over 15 years, they’ve proven to be highly effective and are still frequently observed as a common and viable attack vector these days.

Types of Cross-Site Scripting Attacks

Cross-site scripting attacks are typically categorized as one of the following types.

Reflected XSS

A reflected XSS attack involves a vulnerable website accepting data (i.e. malicious script) sent by the target’s own web browser to attack the target with. Because the malicious script is sent by the client itself and is not stored on the vulnerable server, this type of attack is also referred to as “non-persistent.”

A simple example of a reflected XSS attack could involve an attacker crafting up a URL that passes a small, malicious script as a query parameter to a website that has a search page vulnerable to XSS:

            http://vulnerable-website.com/search?search_term=”<script>(bad things happen here)</script>”

The attacker then needs to have targets visit this URL from their web browsers. This could be accomplished by sending an email containing the URL (with plausible reason to trick the user into clicking it) or publishing the URL to a public, non-vulnerable website for targets to click.

When a target does click the link, the vulnerable site accepts the query parameter “search_term”, expecting that the value is something the target is interested in searching the vulnerable-website.com site for, when in reality the value is the malicious script. The search page then, as most website search pages will do when a user is searching for something, displays “Searching for <seach_term>...”, but because the vulnerable site didn’t sanitize the search_term value, the malicious script is injected into the webpage that the target’s browser is loading and is then executed by the target’s browser.

Persistent XSS

As the name implies, a persistent XSS attack is stored/persisted on the vulnerable server itself. Unlike a reflected attack, where the malicious script is sent by the target, users of a vulnerable website or web app can be attacked during their usual interactions with the vulnerable site/app.

A simple example of a persistent XSS attack could involve an attacker posting a message to a forum hosted on a vulnerable website. Rather than a usual, innocuous forum post, this post content contains the attacker’s malicious script. When a user visits this forum post, their web browser loads and executes the malicious script.

As you can see, a key differentiator between reflected and persistent XSS attacks is that persistent XSS attacks consider all users of a vulnerable site/app as targets for attack.

DOM-Based XSS

Another type of XSS attack is DOM-based, where the vulnerability exists in the client-side scripts that the site/app always provides to visitors. This attack differs from reflected and persistent XSS attacks in that the site/app doesn’t directly serve up the malicious script to the target’s browser. In a DOM-based XSS attack, the site/app has vulnerable client-side scripts which deliver the malicious script to the target’s browser. Similar to a reflected attack, a DOM-based attack does not store the malicious script on the vulnerable server itself.

A simple example of a DOM-based XSS attack could involve the same setup for the reflected XSS example scenario above. The attacker creates a URL with a malicious script as the “search_term” and solicits it to potential targets. Once a target clicks the URL, their browser loads the site search page and the vulnerable client-side processing scripts. While the “seach_term” is still provided as a query parameter to the site back end for processing, the site itself does not generate the web page with the injected malicious script. Instead, the site’s vulnerable client-side scripts are designed to locally (in the target’s browser) dynamically substitute in the search term value (i.e. the malicious script) in the target’s rendered search page, causing the target’s browser to load and execute the attacker’s script.

DOM-based XSS attacks highlight the fact that XSS vulnerabilities aren’t limited to server-side software.

How to Prevent Cross-Site Scripting Attacks

The following suggestions can help safeguard your users against XSS attacks:

Sanitize user input:

  • Validate to catch potentially malicious user-provided input.
  • Encode output to prevent potentially malicious user-provided data from triggering automatic load-and-execute behavior by a browser.

Limit use of user-provided data:

  • Only use where it’s necessary.

Utilize the Content Security Policy:

  • Provides additional levels of protection and mitigation against XSS attempts.

Regularly use a web vulnerability scanning tool to identify XSS vulnerabilities in your software.

While XSS attacks continue to be a popular (and successful) vector of attack, a bit of thoughtful design and testing can go a long way in keeping your website or web application from being vulnerable (and keeping your users protected).