阿里云主机折上折
  • 微信号
Current Site:Index > XSS protection

XSS protection

Author:Chuan Chen 阅读数:48418人阅读 分类: Node.js

Basic Principles of XSS Attacks

XSS (Cross-Site Scripting) is a common web security vulnerability where attackers inject malicious scripts into web pages. When other users visit the page, these scripts execute in their browsers. XSS attacks are primarily divided into three types:

  1. Reflected XSS: Malicious scripts are sent to the server as part of a request, and the server "reflects" the script back in the response.
  2. Stored XSS: Malicious scripts are permanently stored on the target server (e.g., in a database).
  3. DOM-based XSS: The vulnerability exists in client-side code and does not involve server responses.
// A simple reflected XSS example
// Assume the URL is: http://example.com/search?query=<script>alert('XSS')</script>
app.get('/search', (req, res) => {
  const query = req.query.query;
  res.send(`<p>Search results: ${query}</p>`); // Dangerous! Directly outputs user input
});

XSS Protection Measures in Node.js

Input Validation and Filtering

Strict validation of all user input is the first line of defense against XSS. Validation should include:

  • Data type checks
  • Length restrictions
  • Format validation (e.g., email, phone number)
  • Special character filtering
// Using the validator library for input validation
const validator = require('validator');

function sanitizeInput(input) {
  if (typeof input !== 'string') return '';
  // Remove HTML tags
  let clean = validator.stripLow(input);
  clean = validator.escape(clean);
  return clean;
}

app.post('/comment', (req, res) => {
  const comment = sanitizeInput(req.body.comment);
  // Store the processed comment
});

Output Encoding

When outputting data to an HTML page, proper encoding is essential:

  1. HTML entity encoding: Convert special characters to HTML entities.
  2. JavaScript encoding: Use when dynamically generating JavaScript code.
  3. URL encoding: Use for URL parameters.
// Using the he library for HTML entity encoding
const he = require('he');

function safeOutput(text) {
  return he.encode(text, {
    useNamedReferences: true,
    strict: true
  });
}

app.get('/profile', (req, res) => {
  const username = req.query.username || 'Anonymous';
  res.send(`<h1>Welcome, ${safeOutput(username)}</h1>`);
});

Using Secure Template Engines

Modern template engines often include built-in XSS protection:

  • EJS: Escapes output by default.
  • Pug/Jade: Automatically escapes output when using =.
  • Handlebars: Automatically escapes output when using {{}}.
// Example using the EJS template engine
const ejs = require('ejs');

app.set('view engine', 'ejs');

app.get('/product/:id', (req, res) => {
  const product = {
    id: req.params.id,
    name: req.query.name || 'Default Product'
  };
  res.render('product', { product });
});

// product.ejs
<h2><%= product.name %></h2>  <!-- Automatically escaped -->

Setting HTTP Security Headers

Enhance XSS protection by setting HTTP response headers:

// Using the helmet middleware to set security headers
const helmet = require('helmet');

app.use(helmet());
// Equivalent to:
app.use(helmet.xssFilter());          // Sets X-XSS-Protection
app.use(helmet.frameguard());         // Prevents clickjacking
app.use(helmet.noSniff());            // Prevents MIME type sniffing
app.use(helmet.hsts());               // HTTP Strict Transport Security
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", "'unsafe-inline'"],
    styleSrc: ["'self'", "'unsafe-inline'"],
    imgSrc: ["'self'", "data:"]
  }
}));

Implementing CSP (Content Security Policy)

Content Security Policy is one of the most effective modern web application defenses against XSS. It uses a whitelist mechanism to control which resources can be loaded and executed.

// Custom CSP policy
app.use((req, res, next) => {
  res.setHeader(
    'Content-Security-Policy',
    "default-src 'self'; " +
    "script-src 'self' https://trusted.cdn.com 'unsafe-inline'; " +
    "style-src 'self' 'unsafe-inline'; " +
    "img-src 'self' data:; " +
    "font-src 'self'; " +
    "connect-src 'self'; " +
    "frame-src 'none'; " +
    "object-src 'none'"
  );
  next();
});

XSS Protection for Rich Text Content

For user input that requires HTML formatting (e.g., comment systems), more granular filtering is needed:

// Using the xss library to process rich text
const xss = require('xss');

const myxss = new xss.FilterXSS({
  whiteList: {
    a: ['href', 'title', 'target'],
    p: [],
    br: [],
    strong: [],
    em: []
  },
  stripIgnoreTag: true,
  onTagAttr: (tag, name, value) => {
    // Only allow http/https links
    if (tag === 'a' && name === 'href') {
      if (/^https?:\/\//.test(value)) {
        return name + '="' + xss.escapeAttrValue(value) + '"';
      }
      return '';
    }
  }
});

app.post('/rich-comment', (req, res) => {
  const cleanHtml = myxss.process(req.body.content);
  // Store the processed HTML
});

Cookie Security Settings

Prevent cookie theft via XSS attacks:

// Secure cookie settings
app.use(session({
  secret: 'your-secret-key',
  cookie: {
    httpOnly: true,  // Prevents JavaScript access
    secure: true,    // HTTPS only
    sameSite: 'strict', // Prevents CSRF
    maxAge: 24 * 60 * 60 * 1000
  }
}));

Real-Time XSS Detection

Use tools during development to detect XSS vulnerabilities:

// Using the xss-filters library for real-time detection
const xssFilters = require('xss-filters');

app.post('/api/data', (req, res) => {
  const userInput = req.body.input;
  
  try {
    // Throws an exception if XSS attempt is detected
    xssFilters.inHTMLData(userInput);
    
    // Safe processing
    res.json({ status: 'success' });
  } catch (err) {
    // Log XSS attempt
    console.warn('XSS attempt detected:', userInput);
    res.status(400).json({ error: 'Invalid input' });
  }
});

XSS Protection in Frontend Frameworks

Modern frontend frameworks like React, Vue, and Angular have built-in XSS protection mechanisms:

// React example - automatically escapes all variables
function UserProfile({ username }) {
  // Safe, username is automatically escaped
  return <div>Hello, {username}</div>;
}

// Dangerous! Use dangerouslySetInnerHTML with caution
function RichText({ content }) {
  const cleanHtml = sanitize(content); // Must sanitize first
  return <div dangerouslySetInnerHTML={{ __html: cleanHtml }} />;
}

Logging and Monitoring

Logging all potential XSS attack attempts is crucial for security audits:

// Using winston to log security events
const winston = require('winston');
const { Loggly } = require('winston-loggly-bulk');

const logger = winston.createLogger({
  transports: [
    new winston.transports.File({ filename: 'security.log' }),
    new Loggly({
      token: 'your-loggly-token',
      subdomain: 'your-subdomain',
      tags: ['security', 'xss'],
      json: true
    })
  ]
});

app.use((req, res, next) => {
  // Check if the request contains suspicious scripts
  if (JSON.stringify(req.body).includes('<script>')) {
    logger.warn('Potential XSS attempt', {
      url: req.url,
      ip: req.ip,
      payload: req.body
    });
  }
  next();
});

Regular Security Audits

Regular security audits and code reviews are essential for maintaining application security:

  1. Use automated tools to scan for vulnerabilities (e.g., OWASP ZAP, Burp Suite).
  2. Conduct manual code reviews, especially focusing on all user input handling points.
  3. Keep dependencies updated and patch known vulnerabilities promptly.
  4. Perform penetration testing to simulate real attack scenarios.
// Use npm audit to check for dependency vulnerabilities
// package.json
{
  "scripts": {
    "audit": "npm audit --production",
    "audit:fix": "npm audit fix --production"
  }
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:CSRF防护

下一篇:SQL注入防护

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.