Preventing XSS: Best Practices for Frontend Developers
Posted by Nuno Marques on 5 Mar 2025
Introduction
Cross-Site Scripting (XSS) is one of the most common security vulnerabilities in web applications. It allows attackers to inject malicious scripts into a website, which can steal data, hijack sessions, or perform other harmful actions. As a frontend developer, it's crucial to understand how to prevent XSS attacks and protect your users.
In this guide, we’ll break down XSS types, how they work, and the best practices to prevent them.
Estimated reading time: 7 minutes
Understanding XSS Attacks
XSS attacks occur when an application fails to properly sanitize user input, allowing malicious scripts to execute in the browser.
Types of XSS Attacks
- Stored XSS: Malicious script is permanently stored on the server and served to users.
- Reflected XSS: Script is injected via a URL parameter and executed when the link is clicked.
- DOM-based XSS: Malicious script is executed by modifying the webpage's DOM dynamically.
Example of a Reflected XSS Attack
<!-- Vulnerable input field -->
<input id="userInput" type="text">
<button onclick="document.write(userInput.value)">Submit</button>
If an attacker enters <script>alert('XSS Attack!')</script>
, the browser will execute the script instead of treating it as text.
Best Practices to Prevent XSS
1. Sanitize User Input
Use a library like DOMPurify to clean user-generated content.
import DOMPurify from 'dompurify';
const safeHTML = DOMPurify.sanitize(userInput);
document.getElementById("content").innerHTML = safeHTML;
2. Escape Output in HTML, JavaScript, and URLs
- Use
textContent
instead ofinnerHTML
to prevent script execution.
document.getElementById("output").textContent = userInput;
- Escape dynamic URLs using
encodeURI()
.
const safeURL = encodeURI(userInput);
window.location.href = safeURL;
3. Use Content Security Policy (CSP)
CSP restricts the sources from which scripts can be loaded, preventing injected scripts from executing.
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
4. Avoid Inline JavaScript
Never use inline event handlers like onclick="alert('XSS!')"
. Instead, use event listeners.
document.getElementById("btn").addEventListener("click", () => alert("Safe click"));
5. Validate and Sanitize Server-Side
- Always validate input using a strict schema (e.g., Joi in Node.js).
const Joi = require("joi");
const schema = Joi.string().max(100).pattern(/^[a-zA-Z0-9]+$/);
- Sanitize database queries to prevent stored XSS.
6. Use Secure Cookies for Authentication
Storing authentication tokens in Local Storage is risky. Use HttpOnly Secure Cookies instead (Read: How to Secure Your Node.js API with JWT and Cookies).
Key Takeaways
- Sanitize all user input before rendering it on the page.
- Escape dynamic content to prevent script execution.
- Implement a Content Security Policy (CSP) to block unauthorized scripts.
- Avoid inline JavaScript to reduce script injection risks.
- Use Secure Cookies instead of Local Storage for authentication tokens.
Next Steps
- Implement strict input validation on both frontend and backend.
- Use security-focused frameworks like Helmet.js to enforce best practices.
- Regularly audit and test your app for XSS vulnerabilities.