Skip to content

Cross-Site Scripting (XSS)

Cross-Site Scripting (XSS)

Description

Cross-site-scripting (XSS) vulnerabilities occur when unsanitized user-controlled input is served to the user.

XSS vulnerabilities bypass same-Origin-Policy, which is a core principle of web security. SOP ensures that a page from http://evil.com can't access the content of a page from http://bank.com.

XSS is commonly separated into three families

  • Reflected: the user-controlled input is directly reflected in the page response
  • Stored: the user-controlled input is stored on the server side, for instance, in a database, and is later returned to user
  • DOM-based: the user-controlled input is injected on the client-side to the DOM, triggering the injection of malicious JavaScript

XSS vulnerabilities allow an attacker to perform a variety of malicious actions, like exfiltration of personal data, including user session or account information; perform actions on behalf of the user.

Examples

import javax.servlet.http.*;
import java.io.*;

public class VulnerableXSS extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String userInput = request.getParameter("input");
        String page = "<html><body><h2>User Input: " + userInput + "</h2></body></html>";

        PrintWriter out = response.getWriter();
        out.println(page);
    }
}
const express = require('express');
const app = express();

app.get('/vulnerable', (req, res) => {
  const userInput = req.query.input;
  res.send(`<html><body><h2>User Input: ${userInput}</h2></body></html>`);
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});
  <!DOCTYPE html>
  <html>
  <head>
      <title>XSS Vulnerability</title>
  </head>
  <body>
      <h1>Welcome to the Vulnerable Page</h1>
      <p>Search for a product:</p>
      <form action="/search">
          <input type="text" name="query" placeholder="Enter product name">
          <input type="submit" value="Search">
      </form>
      <p>Search results:</p>
      <div id="results">
          <!-- Display search results here -->
          <?php
              // Vulnerable code - directly echoing user input without sanitization
              $query = $_GET['query'];
              echo "<p>You searched for: " . $query . "</p>";
          ?>
      </div>
  </body>
  </html>

Recommendation

In general, cases, preventing XSS vulnerabilities requires 2-step protection:

  • Input validation: user-controlled input should be validated to forbid all unauthorized characters, phone number For instance, only numbers; names should only contain alphabetical characters, etc.
  • Output encoding: all input shown to the user is encoded correctly using proven standard API. Use of a safe template engines with native support for output encoding and secure defaults are highly recommended.

Examples

import org.apache.commons.text.StringEscapeUtils;
import javax.servlet.http.*;
import java.io.*;

public class SecureXSSWithLibrary extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String userInput = request.getParameter("input");
        String sanitizedInput = StringEscapeUtils.escapeHtml4(userInput);
        String page = "<html><body><h2>User Input: " + sanitizedInput + "</h2></body></html>";

        PrintWriter out = response.getWriter();
        out.println(page);
    }
}
const express = require('express');
const app = express();
const { escape } = require('html-escaper'); // Using 'html-escaper' library

app.get('/secure', (req, res) => {
  const userInput = req.query.input;
  const sanitizedInput = escape(userInput);
  res.send(`<html><body><h2>User Input: ${sanitizedInput}</h2></body></html>`);
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});
  <!DOCTYPE html>
  <html>
  <head>
      <title>Secure Page</title>
  </head>
  <body>
      <h1>Welcome to the Secure Page</h1>
      <p>Search for a product:</p>
      <form action="/search">
          <input type="text" name="query" placeholder="Enter product name">
          <input type="submit" value="Search">
      </form>
      <p>Search results:</p>
      <div id="results">
          <!-- Display sanitized search results here -->
          <?php
              // Sanitizing user input before displaying
              $query = $_GET['query'];
              echo "<p>You searched for: " . htmlspecialchars($query, ENT_QUOTES, 'UTF-8') . "</p>";
          ?>
      </div>
  </body>
  </html>

Standards

  • OWASP_ASVS_L1:
    • V5_2_1
    • V5_3_1
    • V13_1_1
  • OWASP_ASVS_L2:
    • V5_2_1
    • V1_5_4
    • V5_3_1
    • V13_1_1
  • OWASP_ASVS_L3:
    • V5_2_1
    • V1_5_4
    • V5_3_1
    • V13_1_1
  • PCI_STANDARDS:
    • REQ_2_2
    • REQ_6_2
    • REQ_6_3
    • REQ_6_4
    • REQ_11_3
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_4_1
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5