When building web applications, one of the most critical aspects of security is handling user input. Unsanitized input is one of the most common entry points for malicious attacks, especially Cross-Site Scripting (XSS) attacks, where attackers inject malicious scripts into web pages.
In this post, we’ll explore how unsanitized input can be exploited, demonstrate a live demo of a vulnerable page, and learn how to prevent these attacks by sanitizing input.
What is Cross-Site Scripting (XSS)?
XSS is a vulnerability that allows attackers to inject malicious scripts into content that is then displayed to other users. This can lead to stolen user data, session hijacking, defacement of websites, or even more severe consequences.
Types of XSS Attacks:
- Stored XSS – The malicious script is stored on the server (in a database, for example) and served to every user who views the affected page.
- Reflected XSS – The script is embedded in a URL and reflected back immediately to the user when they click a link.
- DOM-based XSS – The malicious script is executed directly in the browser, often by manipulating the DOM (Document Object Model).
How an Unsanitized Input is Vulnerable
When a web application directly inserts user input into the page without filtering it first, it opens the door for XSS attacks. Attackers can use this vulnerability to run scripts that can perform harmful actions like stealing cookies, injecting fake login forms, or redirecting users to malicious websites.
The Vulnerable Demo
To illustrate this, we’ll create a simple HTML form where users can input text. In the vulnerable version of this form, the application directly outputs the user input using innerHTML
. This allows attackers to inject JavaScript into the page, which the browser will execute.
Try an XSS Attack!
Type your name below OR try injecting the following script.
<img src="x" onerror="alert('Hacked!')">
This script will trigger an alert when the image fails to load (since "x" is not a valid image source). This is an example of reflected XSS.
⚠️ Vulnerable Code Demo
Output:
Here’s the code for the vulnerable demo:
<form onsubmit="event.preventDefault(); processInput();">
<label for="userInput">Enter text:</label>
<input type="text" id="userInput" placeholder="Type here">
<button type="submit">Submit</button>
</form>
<h3>Output:</h3>
<div id="output"></div>
<script>
function processInput() {
const userInput = document.getElementById("userInput").value;
document.getElementById("output").innerHTML = "You entered: " + userInput;
}
</script>
🛠️ The Fix: Input Sanitization
So, how do we fix this? The key to preventing XSS attacks is sanitizing user input. Sanitization involves cleaning the input data to remove potentially dangerous characters like <, >, and ", which are used in HTML and JavaScript tags.
🔒 Here’s how to sanitize the input and prevent the attack:
function sanitizeHTML(str) {
return str.replace(/</g, "<").replace(/>/g, ">");
}
function processInput() {
const userInput = document.getElementById("userInput").value;
const sanitizedInput = sanitizeHTML(userInput);
document.getElementById("output").textContent = "You entered: " + sanitizedInput;
}
In this version, we use the sanitizeHTML function to replace < and > characters with their HTML entities <
and >
. This ensures that any HTML or JavaScript code entered by the user is displayed as plain text and not executed.
Test the Fix:
Now, when you paste the same script (<img src="x" onerror="alert('Hacked!')">
) into the form, it will not execute the scripts alert. Instead, it will display as:
You entered: <img src="x" onerror="alert('Hacked!')">
The malicious code is displayed as text, not executed, because we've sanitized the input.
Conclusion
Unsanitized user input can leave your site vulnerable to dangerous XSS attacks. Always sanitize and validate user input before displaying it on your web pages. This simple yet crucial step helps to protect your users and your application from potential security breaches.