Reflected, Stored, and DOM-based…
In the landscape of web security, there is one vulnerability that hasn't lost its relevance for years and remains a staple on the OWASP Top 10 list: Cross-Site Scripting, better known as XSS. In this article, we will dissect what XSS is, how threat actors exploit it, and how developers can shield their applications against it.
What is XSS and Why is it Dangerous?
Cross-Site Scripting (XSS) is a security vulnerability that allows an attacker to inject malicious code (typically JavaScript) into a web application that users interact with.
Under normal circumstances, browsers isolate websites from one another using a mechanism called the Same Origin Policy (SOP). However, XSS allows an attacker to bypass this policy.
When an attacker successfully exploits an XSS vulnerability, they can:
- Hijack the victim's session (Session Hijacking).
- Perform unauthorized actions on behalf of the user.
- Access all sensitive data visible to the user.
- Steal the user's keystrokes or passwords.
Types of XSS Attacks
XSS vulnerabilities fall into three main categories. While the logic behind each differs, the outcome is the same: executing malicious code on the victim's machine.
1. Reflected XSS
This is the most common type and is relatively easier to detect. The attacker's malicious code is embedded within an HTTP request sent to the victim (usually via URL parameters), and the server bounces this code back in the response without any sanitization.
Scenario: Imagine a search bar.
URL: https://insecure-website.com/search?term=gift
Response: <p>Search term: gift</p>
If the attacker tweaks the URL like this: https://insecure-website.com/search?term=<script>alert(1)</script>
The server response becomes: <p>Search term: <script>alert(1)</script></p>
When the victim clicks this link, the browser executes the script.
2. Stored XSS (Persistent XSS)
This type is far more dangerous than Reflected XSS because the attack is persistent. The attacker saves the malicious payload directly into the website's database (for example, as a blog comment, a forum post, or profile information).
Subsequently, anyone who visits that page executes the malicious code pulled from the database in their browser. The attacker doesn't need to trick the victim into clicking a specific link; simply visiting the page is enough to trigger the payload.
3. DOM-based XSS
Here, the vulnerability isn't on the server side but entirely within the client-side JavaScript code. It occurs when JavaScript takes user input (source) and processes it insecurely into the HTML (sink) after the page loads.
- Source: Inputs the attacker can manipulate, like
location.searchordocument.referrer. - Sink: Functions that execute code or render HTML, like
innerHTML,document.write, oreval().
Example of vulnerable code:
var search = document.getElementById('search').value;
var results = document.getElementById('results');
results.innerHTML = 'Result: ' + search; // Vulnerability hereWhat Can Be Done with XSS? (Exploitation)
Many people mistakenly think XSS is just about popping an alert(1) box on the screen. However, alert() is merely a "Proof of Concept" tool. In the real world, attackers aim for much more:
- Cookie Stealing: They can steal the victim's session details via
document.cookieand send them to their own servers. However, this can be mitigated if theHttpOnlyflag is set. - Password Capture: Browser "Autofill" features are ubiquitous today. An attacker can inject a fake login form into the page, tricking the browser into filling it out, effectively stealing the password.
- Bypassing CSRF Protection: Since XSS can read the site's CSRF tokens, it allows the attacker to perform actions that are normally protected against CSRF (such as changing an email address).
How Do We Detect XSS Vulnerabilities?
Tools like Burp Suite are the industry standard for hunting down XSS flaws.
- Manual Testing: You inject a simple string containing special characters (e.g.,
halilxss) into every input point (input fields, URL parameters) in the application. Then, you analyze the response to see where and how this string is reflected. - Automated Scanning: Burp Scanner performs both static and dynamic analysis and is quite successful at uncovering hard-to-detect bugs like DOM XSS.
*** Note: Since Chrome v92, the alert() function is blocked in cross-origin iframes. Therefore, using the print() function in your tests might be a more reliable method.
Prevention Methods
Blocking XSS isn't possible with a single line of code; it requires a defense in depth approach.
1. Output Encoding
When writing user-supplied data to the page, you must ensure the browser interprets it as text, not code.
- For HTML Context: Use
<instead of<and>instead of>. - For JavaScript Context: Use Unicode escape sequences (e.g.,
\u003c).
2. Input Validation
Is the data coming from the user in the expected format? For instance, if age is requested, only accept integers. Using an "allow-list" (whitelist) approach for inputs is always safer than a "block-list" (blacklist).
3. Content Security Policy (CSP)
CSP is the final line of defense against XSS. It is an HTTP header returned by the server that tells the browser which resources (scripts, images, styles) are allowed to load.
Example CSP header: Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-scripts.com
This rule allows scripts to run only if they originate from your own domain or the specified trusted domain. Even if an attacker manages to inject a script into the page, CSP will block its execution.
Conclusion
XSS continues to be one of the most prevalent vulnerabilities in web applications. As developers, we must treat all user input as "untrusted," utilize proper encoding methods, and integrate modern security measures like CSP into our applications.
Halil İbrahim Eroğlu