Skip to main content

Asymmetric denial of service - ReDoS

Need

Mitigation of Regular Expression Denial of Service (ReDoS) attacks

Context

  • Usage of TypeScript for static typing and enhanced developer experience in Node.js development
  • 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 searchTerm = req.query.q;

// Vulnerable regular expression
const regex = /^([a-z]+)+$/;

if (regex.test(searchTerm)) {
// Perform search operation
res.send('Search results');
} else {
res.send('Invalid search term');
}
});

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

The vulnerability in this code is an example of an Asymmetric Denial of Service (ReDoS) vulnerability. It is caused by the use of a dangerous regular expression that can lead to a server crash when evaluating certain input strings.

In this code, the regular expression used is /^([a-z]+)+$/. This regular expression is intended to match strings consisting of one or more lowercase letters. However, it is susceptible to a ReDoS attack because of its complexity.

The vulnerability arises from the nested repetition in the regular expression ([a-z]+)+. This allows an attacker to craft a specific input string that triggers exponential backtracking, causing the regular expression engine to spend an excessive amount of time evaluating the string. This can lead to a denial of service by consuming excessive CPU resources and potentially crashing the server.

To mitigate this vulnerability, it is recommended to use optimized regular expressions that do not have excessive complexity or nested repetitions. By using simpler regular expressions, the computational overhead can be reduced, making the code less susceptible to ReDoS attacks.

Steps

  • Replace the vulnerable regular expression with an optimized regular expression.
  • Use a regular expression that has a fixed number of steps to match the input string.
  • Avoid using complex operations or quantifiers that can lead to exponential time complexity.
  • Test the regular expression with various input strings to ensure it performs efficiently.

Compliant code

import express from 'express';

const app = express();

app.get('/search', (req, res) => {
const searchTerm = req.query.q;

// Optimized regular expression
const regex = /^[a-z]+$/;

if (regex.test(searchTerm)) {
// Perform search operation
res.send('Search results');
} else {
res.send('Invalid search term');
}
});

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

The fixed code addresses the vulnerability by using an optimized regular expression to perform the search operation without much computational overhead.

In the code, we import the 'express' module and create an instance of the express application. We define a route for the '/search' endpoint using the HTTP GET method.

Inside the route handler function, we retrieve the search term from the request query parameters using req.query.q.

To mitigate the vulnerability, we use an optimized regular expression const regex = /^[a-z]+$/ to validate the search term. This regular expression ensures that the search term consists only of lowercase alphabets. By using this optimized regular expression, we avoid the potential for catastrophic backtracking and reduce the risk of a denial of service attack.

If the search term passes the regular expression test, we can safely perform the search operation and send the search results as the response using res.send('Search results'). Otherwise, if the search term is invalid, we send a response with the message 'Invalid search term' using res.send('Invalid search term').

Finally, we start the server on port 3000 by calling app.listen(3000, () => {}).

By using an optimized regular expression and validating the search term before performing any complex operations, we ensure that the server is protected against potential denial of service attacks caused by dangerous regular expressions.

References