What is Cross-Site Scripting (XSS)?
Cross-Site Scripting (XSS) is a security vulnerability where an attacker injects malicious scripts (usually JavaScript) into a web page viewed by other users. If the web application doesn't properly handle user-provided data, this script can execute in the victim's browser, allowing the attacker to:
- Steal sensitive information, like session cookies or login tokens.
- Modify the content of the website.
- Redirect the user to a malicious site.
- Perform actions on behalf of the user.
The Golden Rule: The root cause of XSS is an application trusting user input and rendering it directly onto the page without proper sanitization.
A Simple XSS Attack Example
Imagine a comment section on a blog. A user submits a comment, and the server saves it. The next time the page loads, that comment is displayed to all other users.
Vulnerable Code: Let's say the website displays comments like this:
JavaScript
const commentFromDatabase = '<img src="x" onerror="alert(\'XSS Attack! Your cookie is: \' + document.cookie)">';
const commentContainer = document.getElementById('comment-section');
// DANGEROUS: Using .innerHTML with untrusted user input
commentContainer.innerHTML += `<div>${commentFromDatabase}</div>`;
When the browser renders this, it will try to load an image with a source of "x". This will fail, triggering the onerror attribute. The JavaScript inside onerror will then execute in the context of the current user, showing an alert box with their cookie. An attacker could easily change this to send the cookie to their own server.
How to Prevent This: Instead of innerHTML, use textContent. This property treats all input as plain text, not as HTML to be parsed.
JavaScript
// SAFE: .textContent inserts the content as plain text
const commentDiv = document.createElement('div');
commentDiv.textContent = commentFromDatabase; // The <img...> tag is rendered as literal text
commentContainer.appendChild(commentDiv);
Defense in Depth: Content Security Policy (CSP)
While always sanitizing user input is the primary defense, mistakes can happen. A Content Security Policy (CSP) is an added layer of security (an HTTP response header) that tells the browser which sources of content are trusted and allowed to be executed.
A CSP acts as a whitelist. If an attacker manages to inject a script, the CSP can block the browser from executing it.
How it Works The web server sends a Content-Security-Policy header along with the web page.
Example Policy: Content-Security-Policy: default-src 'self'; script-src 'self' https://apis.google.com;
Let's break this down:
- default-src 'self': By default, only allow content (images, fonts, etc.) to be loaded from the same origin (domain) as the website itself. 'self' is a special keyword.
- script-src 'self' https://apis.google.com;: This overrides the default for scripts. It allows scripts to be loaded from the same origin ('self') AND from https://apis.google.com.
If an attacker injects an inline script (<script>alert('pwned')</script>) or a script from a malicious domain (<script src="https://evil.com/hax.js"></script>), the browser will see that neither source is in the script-src whitelist and will refuse to execute the script.
CSP is a powerful tool to mitigate the risk of XSS attacks, even if a vulnerability exists in your code.