🔐Encoding & Escaping
XSS Attack Prevention
Prevent Cross-Site Scripting (XSS) attacks with proper escaping and sanitization
Explanation
XSS prevention requires context-aware escaping, Content Security Policy, and sanitizing user-generated HTML.
Examples
Vulnerable code
Input
innerHTML = userInput
Output
⚠️ XSS risk!
Safe approach
Input
textContent = userInput
Output
✓ No HTML parsing
Code Examples
JavaScript
// ❌ VULNERABLE - innerHTML with user input
element.innerHTML = userInput; // XSS risk!
// ✅ SAFE - textContent (no HTML parsing)
element.textContent = userInput;
// ✅ SAFE - React (auto-escapes by default)
function Component({ userInput }) {
return <div>{userInput}</div>; // Escaped automatically
}
// ❌ VULNERABLE - React dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={{ __html: userInput }} />
// ✅ SAFE - Sanitize HTML with DOMPurify
import DOMPurify from 'dompurify';
const cleanHtml = DOMPurify.sanitize(userInput);
element.innerHTML = cleanHtml;
// ✅ SAFE - Vue (auto-escapes by default)
<template>
<div>{{ userInput }}</div> <!-- Escaped -->
<div v-text="userInput"></div> <!-- Escaped -->
<div v-html="sanitizedHtml"></div> <!-- Use with DOMPurify -->
</template>
// Context-aware escaping
function escapeHtml(str) {
return str.replace(/[&<>"']/g, m => ({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
})[m]);
}
function escapeAttribute(str) {
return str
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function escapeJs(str) {
return str
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/'/g, "\\'")
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/</g, '\\u003c')
.replace(/>/g, '\\u003e');
}
// URL context
function escapeUrl(url) {
// Only allow http/https protocols
if (!url.match(/^https?:\/\//)) {
return '';
}
return encodeURI(url);
}
// Content Security Policy (CSP) headers
// Set in server config or meta tag
const cspHeader = "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'";
// ✅ Safe data attribute approach
element.dataset.userInput = userInput;
const safe = element.dataset.userInput; Python
import html
from markupsafe import escape, Markup
# ❌ VULNERABLE - Direct string interpolation in templates
template = f"<div>{user_input}</div>" # XSS risk!
# ✅ SAFE - Jinja2 auto-escaping
from jinja2 import Template
template = Template('<div>{{ user_input }}</div>')
safe_html = template.render(user_input=user_input)
# ✅ SAFE - Django templates (auto-escape by default)
# In template: {{ user_input }}
# ✅ SAFE - Manual escaping
escaped = html.escape(user_input)
# ✅ SAFE - Sanitize HTML with bleach
import bleach
allowed_tags = ['p', 'br', 'strong', 'em', 'a']
allowed_attrs = {'a': ['href', 'title']}
clean_html = bleach.clean(
user_input,
tags=allowed_tags,
attributes=allowed_attrs,
strip=True
)
# Context-specific escaping
def escape_js(text):
return (text
.replace('\\', '\\\\')
.replace('"', '\\"')
.replace("'", "\\'")
.replace('\n', '\\n')
.replace('\r', '\\r')
.replace('<', '\\u003c')
.replace('>', '\\u003e'))💡 Tips
- Use framework auto-escaping (React, Vue, Angular)
- textContent is safer than innerHTML
- Sanitize HTML with DOMPurify or bleach
- Implement Content Security Policy (CSP)
- Validate input on both client and server
- Escape for context (HTML, attribute, JS, CSS, URL)
- Use httpOnly cookies for session tokens
- Never trust user input
- Disable inline scripts with CSP
⚠️ Common Pitfalls
- innerHTML with user input = XSS
- eval() with user input = code execution
- href="javascript:..." = XSS
- onclick= attributes with user input = XSS
- Wrong context escaping (HTML in JS context)
- Incomplete sanitization leaves vulnerabilities
- Double encoding can bypass filters
- DOM-based XSS in client-side code