Introduction
F5 Labs attack series articles help you understand common attacks, how they work, and how to guard against them.
What Is Cross-Site Scripting?
Cross-site scripting, commonly referred to as XSS, is one of many types of insertion attacks1 that affect web-based applications and, by extension, their users. It occurs when a vulnerability in an application enables an attacker to insert a malicious script—typically JavaScript—into the vulnerable website’s code. Once the script is inserted, a user’s browser automatically runs the script when he or she visits the affected website. The script can be designed to carry out a variety of malicious acts, leaving the unsuspecting user vulnerable to potential cookie, credential, data, or identity theft; account takeover; malware infection; even full compromise of the user’s system. As such, XSS attacks violate the first two (and potentially all three) of security's foundational CIA triad principles: confidentiality, integrity, and availability.
Given that the malicious script runs client-side in the user’s browser (as opposed to server-side on the web server itself), the website isn’t the ultimate target, its users are. Most users trust that the responses they receive from a web application are legitimately generated by the app and not by a malicious actor. Cross-site scripting exploits that trust. The insidious thing about XSS attacks is that users can become victims simply by unknowingly visiting a compromised website. It’s not obvious or visible to the user that a website has been tampered with, and as long as the website remains compromised, every new visitor will potentially be affected by it.
What Makes a Website Vulnerable to Cross-Site Scripting?
Websites and web-based applications that are vulnerable to XSS are generally those that accept user input in login pages, search boxes, comment fields, sign-up forms, or forms requesting name, address, phone, and credit card numbers. It’s hard to imagine a website today that doesn’t incorporate at least one of these components.
A web application should never automatically trust input from a user without first validating it. That means the application should only accept the “right” kind of input based on what’s expected or asked, for example, exactly five numeric digits for a U.S. zip code, or exactly 16 numeric digits for a credit card number. In addition, it should not accept any kind of input that includes special characters used in code or commands. A website is vulnerable to XSS attack when it doesn’t validate input that is then used in the output (responses) the application sends back to the user. It’s this failure to validate input that enables an attacker to insert a malicious script into the website code. (This is essentially the same type of vulnerability that makes SQL injection attacks possible. The difference with XSS is that the inserted code runs in the user’s browser whereas malicious SQL commands target a website’s database and are sent directly through for processing.)
Types of Cross-Site Scripting Attacks
There are three primary types of cross-site scripting attacks: stored, reflected, and DOM-based. Regardless of type, all three follow the same fundamental attack sequence: (1) an attacker searches for sites that have XSS vulnerabilities, (2) the attacker inserts malicious code into a vulnerable webpage, and (3) when the unsuspecting user interacts with the website, that malicious code is sent to the user’s browser, where it runs automatically.
Persistent (Stored) XSS Attacks
Persistent XSS attacks generally target websites like online communities and Internet forums (also known as message, bulletin, or discussion boards; guest books; social networking platforms) that accept user-generated content. An attacker, for example, posts a seemingly innocuous comment, but the comment contains a malicious script. Later, when a user views that comment (the script itself is not visible), the user’s browser runs the script automatically.
Persistent XSS attacks—more commonly known as “stored” because the malicious code is saved on the web server or in a database—are considered the most dangerous type because any visitor who views the comment becomes an unwitting victim. The attacker doesn’t need to use any tactics to trick or deceive the user.
Reflected XSS Attacks
Reflected XSS attacks (also known as non-persistent) generally occur in websites that mirror information back to the user, for example, the results of a search query, or a greeting such as Welcome [name]! after the user logs in. Unlike stored XSS, reflected XSS attacks involve deception; the attacker must find a way to trick the user into clicking on a malicious link that runs an HTTP command, which then triggers the malicious script. The challenge is in getting the victim to trust that the malicious link is legitimate; often it’s included in an innocent looking email from a source the user trusts.
In one example of a reflected attack, the malicious script could be designed to steal the user’s session cookie, enabling the attacker to impersonate the user and take any action he or she would normally be able to perform while using the application. Imagine if the user was logged into a banking website, the attacker could transfer all of the user’s funds to an account under his or her control. Since the attacker is using a legitimate session cookie (albeit stolen) and appears to be logged in as the real user, there’s nothing suspicious about this transaction that would raise any red flags.
DOM-Based XSS Attacks
Every webpage has a Document Object Model (DOM) that describes the components (things like the title, headings, tables, forms, links, etc.) and logical structure of the HTML page. The browser builds and updates the DOM as it retrieves a webpage and runs scripts. A DOM-based XSS attack is similar to a reflected XSS attack in that the malicious code runs in the browser. The difference is that the code is inserted into the DOM rather than the website. The DOM is just one more place for an attacker to hide a malicious script.