XSS (Cross-Site Scripting) Attack Vectors & Defense Guide
Khái Niệm XSS (Cross-Site Scripting)
XSS là gì?
XSS (Cross-Site Scripting) là một lỗ hổng bảo mật web cho phép kẻ tấn công chèn và thực thi mã JavaScript độc hại trong trình duyệt của người dùng khác. Lỗ hổng này xảy ra khi ứng dụng web:
- Nhận input từ user (form, URL parameters, cookies...)
- Không validate/sanitize input đó đúng cách
- Hiển thị input trực tiếp lên trang web mà không escape
- Cho phép browser execute nội dung như HTML/JavaScript
Tại sao XSS nguy hiểm?
🔥 Tác hại tiềm tàng:
- 🍪 Đánh cắp Session/Cookies:
document.cookie
→ Account takeover - 🎯 Keylogging: Capture mọi keystroke của user
- 🎪 Phishing: Inject fake login forms để steal credentials
- 💰 Unauthorized Actions: Transfer money, change password thay mặt user
- 🕵️ Data Exfiltration: Steal sensitive information từ DOM
- 🤖 Botnet Creation: Turn user browser thành zombie bot
- 📱 Drive-by Downloads: Force download malware
🧠 Tại sao dễ bị tấn công?
- Trust Model: Browser tin tưởng mọi script từ same origin
- User Trust: User tin tưởng website legitimate
- Complex Input: Modern web có nhiều input sources (URL, forms, APIs...)
- Developer Oversight: Developers often forget to sanitize edge cases
3 Loại XSS Chính:
1. 🎯 Stored XSS (Persistent)
- Cách hoạt động: Malicious script được lưu vào database/server
- Kích hoạt: Mỗi khi user khác view content bị nhiễm
- Ví dụ: Comment, forum post, user profile chứa script
- Mức độ: CỰC KỲ NGUY HIỂM - affect nhiều victims
2. 🏹 Reflected XSS (Non-Persistent)
- Cách hoạt động: Script trong URL/form được reflect ngay lập tức
- Kích hoạt: User click vào malicious link
- Ví dụ: Search results, error messages từ URL parameters
- Mức độ: NGUY HIỂM - require social engineering
3. 🎭 DOM-Based XSS
- Cách hoạt động: JavaScript modify DOM với untrusted data
- Kích hoạt: Client-side code process malicious input
- Ví dụ:
document.write()
,innerHTML
với user input - Mức độ: NGUY HIỂM - bypass server-side filters
📋 Tóm Tắt Các Attack Vectors Đã Kiểm Nghiệm
🔴 1. Event Handler Injection (onclick, onload, onerror)
Cách Hacker Sử Dụng:
<img src=x onclick="(function(){var o=window.fetch;window.fetch=function(){console.log('Intercepted:',arguments);return o.apply(this,arguments)};})()\">
🧠 Giải thích chi tiết:
Anatomy của attack:
<img src=x>
- Tạo invalid image element (src=x sẽ fail to load)onclick="..."
- Event handler chạy khi user click vào image(function(){...})()
- Immediately Invoked Function Expression (IIFE) để encapsulate codevar o=window.fetch
- Backup original fetch functionwindow.fetch=function(){...}
- Override global fetch với malicious versionconsole.log('Intercepted:',arguments)
- Log tất cả fetch calls để spyreturn o.apply(this,arguments)
- Call original fetch để maintain functionality
Mục đích:
- 🎯 API Interception: Monitor mọi HTTP requests (GET, POST, PUT...)
- 🔑 Token Theft: Steal Authorization headers, API keys
- 📊 Data Monitoring: Log request payloads, responses
- 🕵️ Persistent Spying: Continues monitoring sau khi page load
- 🎭 Stealth Attack: Không có alert() obvious, hard to detect
✅ Cách Khắc Phục:
// 1. Server-side sanitization
const DOMPurify = require('isomorphic-dompurify');
const clean = DOMPurify.sanitize(dirty, {
FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover', 'onfocus']
});
// 2. Regex để loại bỏ on* attributes
const sanitized = userInput.replace(/\s*on\w+\s*=\s*[^>]*/gi, '');
// 3. CSP Header
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
🔴 2. Image Source Manipulation với Event Handlers
Cách Hacker Sử Dụng:
<img src="https://valid-image-url.jpg" onload="(function(){var o=window.fetch;window.fetch=function(){console.log('Intercepted:',arguments);return o.apply(this,arguments)};})()\">
🧠 Giải thích chi tiết:
Tại sao attack này tinh vi:
- Legitimate Image Source: Sử dụng URL ảnh thật từ domain tin cậy
- Bypass Content Filters: Security tools thường whitelist trusted domains
- Automatic Execution:
onload
trigger ngay khi image load (không cần user interaction) - Social Engineering: User thấy ảnh bình thường, không nghi ngờ
- Persistent Hook: Sau khi execute, mọi fetch() đều bị intercept
Kỹ thuật nâng cao:
- Domain Reputation Abuse: Exploit trust của legitimate CDN domains
- Content-Type Confusion: Server serve image nhưng browser execute script
- Cache Poisoning: Nếu image được cache, attack persist longer
- Steganography: Hide malicious code trong image metadata
Mục đích:
- 🎭 Stealth Monitoring: User không biết đang bị spy
- 🔒 Session Hijacking: Intercept authentication requests
- 💰 Financial Fraud: Monitor banking/payment API calls
- 📱 Cross-Origin Data Theft: Steal data từ other domains (if CORS misconfigured)
✅ Cách Khắc Phục:
// 1. Whitelist allowed image domains
const allowedDomains = ['yoursite.com', 'cdn.yoursite.com'];
const isValidImageUrl = (url) => {
const domain = new URL(url).hostname;
return allowedDomains.includes(domain);
};
// 2. Strip all event handlers
const stripEventHandlers = (html) => {
return html.replace(/\s*on\w+\s*=\s*["'][^"']*["']/gi, '');
};
// 3. Content Security Policy
Content-Security-Policy: img-src 'self' https://trusted-cdn.com;
🔴 3. Data URI với SVG Script Injection
Cách Hacker Sử Dụng:
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' onload='alert(1)'></svg>">
🧠 Giải thích chi tiết:
Cấu trúc của Data URI Attack:
data:
- Data URI scheme cho phép embed content trực tiếpimage/svg+xml
- MIME type báo cho browser đây là SVG image<svg xmlns='...'>
- Valid SVG element với namespace declarationonload='alert(1)'
- Event handler execute khi SVG load- Browser Parsing: Browser parse SVG và execute embedded script
Tại sao attack này dangerous:
- 🎭 Mime Type Spoofing: Disguise executable content như image
- 🚫 Filter Bypass: Content filters thường allow "image" files
- 📤 No External Resource: Không cần host malicious file externally
- 🔄 Self-Contained: Toàn bộ attack payload trong single string
- 📱 Cross-Platform: Work trên mọi browser hỗ trợ SVG
Advanced SVG Attack Vectors:
<!-- Animation-based execution -->
<svg><animate attributeName="onload" values="alert(1)">
<!-- ForeignObject with HTML -->
<svg><foreignObject><html><script>alert(1)</script></html></foreignObject></svg>
<!-- CSS-based execution -->
<svg><style>*{-webkit-animation:spin 1s;-webkit-animation-name:spinteger;}</style></svg>
Mục đích:
- 🎯 File Upload Bypass: Upload "image" file thực chất là script
- 🌐 Email Attachment Attack: Send malicious "image" via email
- 📊 Data Exfiltration: SVG có thể fetch external resources
- 🔗 Chaining Attacks: Combine với other vectors để amplify impact
✅ Cách Khắc Phục:
// 1. Disable data URIs hoàn toàn
const sanitizeImageSrc = (src) => {
if (src.startsWith('data:')) {
throw new Error('Data URIs not allowed');
}
return src;
};
// 2. Nếu cần data URI, chỉ cho phép specific types
const allowedDataTypes = ['data:image/png', 'data:image/jpeg', 'data:image/gif'];
const isValidDataUri = (src) => {
return allowedDataTypes.some(type => src.startsWith(type));
};
// 3. Server-side SVG sanitization
const sanitizeSVG = require('svg-sanitizer');
const cleanSVG = sanitizeSVG(svgContent, {
removeScriptElements: true,
removeEventHandlers: true
});
// 4. CSP Policy
Content-Security-Policy: img-src 'self' data: https:; object-src 'none';
🔴 4. Link Manipulation Attacks
Cách Hacker Sử Dụng:
<a href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js">Click me</a>
🧠 Giải thích chi tiết:
Anatomy của Social Engineering Attack:
- Legitimate Domain:
cdn.jsdelivr.net
là CDN tin cậy, users often trust - Familiar Library: Bootstrap là thư viện popular, không gây nghi ngờ
- Deceptive Text: "Click me" neutral, không hint về danger
- Direct Download: Link point trực tiếp đến executable JavaScript file
- Auto-Execute: Một số browsers sẽ execute JS files directly
Psychological Manipulation:
- 🎯 Trust Exploitation: Abuse user trust trong familiar brands
- 🎭 Authority Deception: Pretend to be legitimate resource
- ⚡ Urgency Creation: "Update required", "Security patch"
- 🔗 Link Obfuscation: Show different URL than actual destination
Advanced Link Manipulation Techniques:
<!-- JavaScript protocol injection -->
<a href="javascript:eval(atob('YWxlcnQoJ1hTUycp'))">Safe Link</a>
<!-- Target manipulation for phishing -->
<a href="http://evil.com" target="_blank">Continue to PayPal</a>
<!-- CSRF via image in link -->
<a href="http://bank.com/transfer?amount=1000&to=hacker"><img src="safe-image.jpg"></a>
<!-- Data URI with HTML -->
<a href="data:text/html,<script>location.href='http://evil.com'</script>">Document</a>
Mục đích:
- 💾 Malware Distribution: Force download trojan, keylogger, ransomware
- 🎣 Credential Phishing: Redirect to fake login pages
- 🏦 Financial Fraud: Trick users into authorizing transactions
- 📱 Mobile Exploitation: Mobile users ít careful về links
- 🤖 Botnet Recruitment: Install remote access tools
✅ Cách Khắc Phục:
// 1. Validate và whitelist domains
const trustedDomains = ['yoursite.com', 'github.com', 'official-cdn.com'];
const validateLink = (href) => {
const url = new URL(href);
return trustedDomains.includes(url.hostname);
};
// 2. Add rel="noopener noreferrer"
const sanitizeLinks = (html) => {
return html.replace(/<a\s+href=/gi, '<a rel="noopener noreferrer" href=');
};
// 3. Content Security Policy
Content-Security-Policy: default-src 'self'; frame-ancestors 'none';
// 4. X-Frame-Options
X-Frame-Options: DENY
🎓 Tại sao XSS Attack thành công?
🧠 Factors góp phần vào XSS vulnerabilities:
1. 👨💻 Developer Factors:
- Lack of Security Awareness: Không hiểu risk của user input
- Time Pressure: Rush to ship features without security review
- Complex Codebase: Hard to track all input/output points
- Framework Misuse: Bypass built-in security features
- Copy-Paste Code: Inherit vulnerabilities từ untrusted sources
2. 🏗️ Architecture Factors:
- Client-Side Validation Only: Rely solely on frontend checks
- Mixed Content Sources: Data từ nhiều sources không consistent sanitization
- Legacy System Integration: Old systems không có modern security
- Microservices Complexity: Hard to maintain security across services
- Third-Party Dependencies: Vulnerable libraries, widgets, scripts
3. 🎯 User Factors:
- Trust Assumption: Users trust familiar websites
- Security Fatigue: Ignore security warnings
- Social Engineering Susceptibility: Fall for convincing attacks
- Device Limitations: Mobile users harder to spot suspicious activity
- Browser Diversity: Different browsers handle security differently
🔄 XSS Attack Lifecycle:
1. 🎯 Reconnaissance
├─ Find input fields (forms, search, comments)
├─ Test for output reflection
├─ Identify filtering mechanisms
└─ Map application attack surface
2. 🧪 Payload Development
├─ Craft bypass techniques
├─ Test different encoding methods
├─ Develop browser-specific exploits
└─ Create social engineering hooks
3. 💥 Exploitation
├─ Inject malicious payload
├─ Trigger execution condition
├─ Establish persistence
└─ Exfiltrate sensitive data
4. 🎭 Post-Exploitation
├─ Maintain access (stored XSS)
├─ Lateral movement to other users
├─ Data harvesting operations
└─ Cover tracks / avoid detection
🛡️ Comprehensive Defense Strategy
1. Input Sanitization (Server-Side Priority)
🎯 Nguyên tắc Defense in Depth:
- 📥 Input Validation: Validate format, length, character set
- 🧹 Sanitization: Remove/escape dangerous content
- 🔒 Output Encoding: Encode khi display ra browser
- 🛡️ CSP Protection: Browser-level script execution control
// Node.js với DOMPurify - GOLD STANDARD
const createDOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);
const sanitizeHTML = (dirty) => {
return DOMPurify.sanitize(dirty, {
// Chỉ cho phép safe tags
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'ol', 'ul', 'li'],
// Chỉ cho phép safe attributes
ALLOWED_ATTR: ['class', 'id'],
// Cấm tất cả event handlers
FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover', 'onfocus', 'onblur'],
// Cấm dangerous tags
FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'svg', 'math', 'style'],
// Additional security options
SANITIZE_DOM: false, // Don't sanitize DOM nodes
KEEP_CONTENT: false, // Remove content of forbidden tags
ALLOW_DATA_ATTR: false // No data-* attributes
});
};
// Multi-layer validation example
const validateUserInput = (input) => {
// 1. Length validation
if (input.length > 1000) {
throw new Error('Input too long');
}
// 2. Character whitelist (for strict inputs)
const allowedChars = /^[a-zA-Z0-9\s\.\,\!\?\-]+$/;
if (!allowedChars.test(input)) {
throw new Error('Invalid characters detected');
}
// 3. Sanitization
const sanitized = sanitizeHTML(input);
// 4. Additional checks after sanitization
if (sanitized.includes('javascript:') || sanitized.includes('data:')) {
throw new Error('Suspicious protocol detected');
}
return sanitized;
};
2. Content Security Policy (CSP)
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-random123';
img-src 'self' https://trusted-cdn.com;
style-src 'self' 'unsafe-inline';
object-src 'none';
frame-src 'none';
base-uri 'self';
form-action 'self';
report-uri /csp-report-endpoint;
3. HTTP Security Headers
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()
4. Secure Cookies
// Set secure cookie flags
app.use(session({
cookie: {
httpOnly: true, // Prevent XSS cookie theft
secure: true, // HTTPS only
sameSite: 'strict' // CSRF protection
}
}));
5. Angular-Specific Protection
// Component sanitization
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Component({...})
export class SecureComponent {
constructor(private sanitizer: DomSanitizer) {}
// NEVER do this - bypasses Angular security
// getTrustedHtml(html: string): SafeHtml {
// return this.sanitizer.bypassSecurityTrustHtml(html);
// }
// CORRECT: Use interpolation instead
displayContent(userInput: string): string {
// Angular automatically sanitizes {{ }} interpolation
return userInput;
}
}
6. Client-Side Validation (Backup Only)
// Additional client-side checks (not primary defense)
const clientSideSanitize = (input) => {
// Remove javascript: protocols
input = input.replace(/javascript:/gi, '');
// Remove data: URIs except safe image types
input = input.replace(/data:(?!image\/(png|jpe?g|gif))/gi, '');
// Remove event handlers
input = input.replace(/\s*on\w+\s*=/gi, '');
return input;
};
⚠️ Critical Security Reminders
🚨 Never Trust Client-Side Validation
- Always validate and sanitize on server-side
- Client-side checks are easily bypassed
- Treat all user input as hostile
🚨 Code Review Checklist
- No
innerHTML
with user input - No
eval()
,new Function()
,setTimeout(string)
- No
document.write()
with user data - All user input sanitized server-side
- CSP headers properly configured
- Cookies have security flags
- No
bypassSecurityTrust*
methods used
🚨 Incident Response Plan
- Detect: Monitor CSP violation reports
- Contain: Block malicious IPs, disable affected features
- Investigate: Check logs, identify attack vectors
- Remediate: Patch vulnerabilities, update security policies
- Learn: Update security guidelines, train developers
🎯 Testing Your Defenses
XSS Test Payloads:
<!-- Basic tests -->
<script>alert('xss')</script>
<img src=x onerror=alert('xss')>
<svg onload=alert('xss')></svg>
<!-- Advanced tests -->
<iframe srcdoc="<script>alert('xss')</script>"></iframe>
<object data="data:text/html,<script>alert('xss')</script>"></object>
<a href="javascript:alert('xss')">click</a>
<!-- Filter bypass attempts -->
<IMG SRC=x ONERROR=alert('xss')>
<img src=x onerror=alert('xss') >
<img/src=x/onerror=alert('xss')>
📚 XSS Mitigation Strategies by Context
� Context-Aware Output Encoding:
// HTML Context: &, <, >, ", ' cần escape
const escapeHTML = (str) => {
return str.replace(/[&<>"']/g, (match) => {
const escape = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return escape[match];
});
};
// JavaScript Context: Escape for JS string
const escapeJS = (str) => {
return str.replace(/[\\'"]/g, '\\$&')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\t/g, '\\t');
};
// URL Context: URL encode
const escapeURL = (str) => {
return encodeURIComponent(str);
};
// CSS Context: Escape CSS values
const escapeCSS = (str) => {
return str.replace(/[^a-zA-Z0-9]/g, '\\$&');
};
🏆 XSS Prevention Maturity Model
Level 1: Basic Protection 🥉
- Server-side input validation
- Basic HTML escaping trong templates
- CSP header implementation
- HttpOnly cookies
Level 2: Intermediate Security 🥈
- Context-aware output encoding
- DOMPurify integration
- Automated security scanning
- Security headers suite
- Regular dependency updates
Level 3: Advanced Defense 🥇
- Nonce-based CSP với auto-rotation
- Subresource Integrity (SRI) verification
- Content sanitization pipeline
- Real-time XSS detection & blocking
- Security team review process
Level 4: Expert Level 🏆
- Custom CSP violation monitoring
- ML-based anomaly detection
- Zero-trust content processing
- Security bug bounty program
- Regular penetration testing
🚨 Emergency Response Checklist
Khi phát hiện XSS attack:
⚡ Immediate Actions (0-1 hour):
- Identify affected pages/components
- Block malicious IPs từ WAF/Cloudflare
- Disable vulnerable features nếu cần thiết
- Alert security team và management
- Document attack vector và impact
🔧 Short-term Fixes (1-24 hours):
- Apply emergency patches
- Update CSP để block attack vectors
- Invalidate potentially compromised sessions
- Monitor for continued attacks
- Communicate với affected users
🛡️ Long-term Remediation (1-7 days):
- Code review để tìm similar vulnerabilities
- Update security guidelines
- Implement additional monitoring
- Security training cho development team
- Third-party security audit
🎖️ Conclusion: XSS là một trong những attack vectors nguy hiểm và phổ biến nhất. Hiểu rõ cách thức hoạt động và implement defense đúng cách là crucial để bảo vệ users và business. Defense in Depth với multiple layers security sẽ provide protection tốt nhất trước evolving XSS techniques.
All rights reserved