Skip to main content

Reflected cross-site scripting (XSS)

Need

Implementation of input validation and output encoding to prevent the execution of malicious scripts

Context

  • Usage of TypeScript for type-checking and compiling JavaScript code
  • Usage of Express for building web applications and APIs

Description

Non compliant code

import express from 'express';

const app = express();

app.get('/search', (req, res) => {
const query = req.query.q;
res.send(`<h1>Search Results for: ${query}</h1>`);
});

app.listen(3000, () => {
console.log('Server started on port 3000');
});

The vulnerability in the provided code is a Reflected Cross-Site Scripting (XSS) vulnerability. This vulnerability occurs because the code dynamically generates web content without properly validating or sanitizing the user input.

In the vulnerable code, the Express.js route handler for the '/search' endpoint retrieves the value of the 'q' query parameter from the request object using req.query.q. This value is then directly interpolated into an HTML string using template literals and sent back as a response using res.send().

This means that if an attacker crafts a malicious query parameter value, it will be reflected back in the response HTML without any validation or sanitization. This can lead to the execution of arbitrary JavaScript code in the context of the victim's browser when they visit the '/search' endpoint.

For example, if an attacker sends a request with the query parameter '?q=', the response will include the script tag, resulting in an alert dialog being displayed to the user.

To mitigate this vulnerability, it is recommended to perform proper input data validation and sanitization on the server-side. This can involve using a library or framework-specific input validation mechanism or implementing custom validation logic to ensure that user input is safe before using it to generate dynamic content.

Steps

  • Validate and sanitize the input data received from the client-side.
  • Use a library or built-in functions to escape or encode the input data before including it in the response.
  • Update the code to use a template engine or a safer way to generate dynamic content.
  • Implement Content Security Policy (CSP) to restrict the execution of scripts from external sources.

Compliant code

import express from 'express';
import { escape } from 'html-escaper'; // Import the library for escaping HTML characters

const app = express();

app.get('/search', (req, res) => {
const query = escape(req.query.q); // Escape the input data
res.send(`<h1>Search Results for: ${query}</h1>`);
});

app.listen(3000, () => {
console.log('Server started on port 3000');
});

The fixed code addresses the vulnerability of Reflected Cross-Site Scripting (XSS) by implementing proper input data validation on the server-side.

  1. The code imports the necessary modules, including the 'express' module for creating the server and the 'html-escaper' module for escaping HTML characters.

  2. An instance of the express application is created.

  3. The code defines a route for the '/search' endpoint using the HTTP GET method. This route handles the search functionality.

  4. Inside the route handler, the input data from the query parameter 'q' is retrieved using 'req.query.q'.

  5. The 'escape' function from the 'html-escaper' module is used to escape any HTML characters in the input data. This helps prevent any potential script injection attacks.

  6. The escaped input data is then used to generate the search results HTML response. The response includes the escaped input data in the &lt;h1> tag.

  7. The server listens on port 3000 for incoming requests.

By using the 'escape' function to properly escape HTML characters in the input data, the fixed code ensures that any potential malicious scripts injected into untrusted data will be rendered harmless when displayed in the web page.

References