DEV Community

Cover image for Using Regex with Express
Jake Roggenbuck
Jake Roggenbuck

Posted on

Using Regex with Express

This is a brief introduction to using Regex validation in an Express backend. We will be using the new Regex library called Regolith that prevents Regular Expression Denial of Service Attacks when creating Regex patterns. More information about this library is shared below or on the GitHub page.

Project Setup

Start by creating a project in your terminal:

mkdir express-example
Enter fullscreen mode Exit fullscreen mode

Navigate in to the newly created project:

cd express-example
Enter fullscreen mode Exit fullscreen mode

Initialize the JavaScript Project:

npm init
Enter fullscreen mode Exit fullscreen mode

Fill in the details for the new project. You can also just press enter for every field for the default (which is fine).

Install Express and Regolith:

npm i express @regolithjs/regolith
Enter fullscreen mode Exit fullscreen mode

Edit the contents of package.json and change type: "commonjs" to type: "module" to allow us to use the module import syntax.

It should end up looking something like this:

{
  "name": "express-example",
  "version": "1.0.0",
  "description": "",
  "license": "ISC",
  "author": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "@regolithjs/regolith": "^0.1.4",
    "express": "^5.1.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Writing the code

Create a file that will contain all of our code called index.js in your favorite editor.

Open the file and then add the following code:

import express from "express";

console.log(express);
Enter fullscreen mode Exit fullscreen mode

Now when we run the code with node index.js, we should see the following:

[Function: createApplication] {
  application: {
    init: [Function: init],
    defaultConfiguration: [Function: defaultConfiguration],

  // ...

  text: [Function: text],
  urlencoded: [Function: urlencoded]
}
Enter fullscreen mode Exit fullscreen mode

This shows us that Express was imported and installed correctly.

We can now add some basic Express code to our index.js:

import express from "express";
import { Regolith } from "@regolithjs/regolith";

const app = express();
const port = 3000;

console.log("Show Regolith is installed correctly:", Regolith);

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});
Enter fullscreen mode Exit fullscreen mode

Run the code with node index.js and we should see the server start up:

Show Regolith is installed correctly. [Function: Regolith]
Example app listening on port 3000
Enter fullscreen mode Exit fullscreen mode

This also shows us that Regolith is installed correctly.

Now we can create Regex patterns with Regolith that check if a provided input matches either the int pattern or the float pattern. Imagine we wanted to create a basic server that helps us validate different types of numbers.

import express from "express";
import { Regolith } from "@regolithjs/regolith";

const app = express();
const port = 3000;

// Create Regolith Regex patterns
const intPattern = new Regolith("^\\d+$");
const floatPattern = new Regolith("^\\d*\\.\\d+$");

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});
Enter fullscreen mode Exit fullscreen mode

Now we can test to see if our new Regex patterns work:

import express from "express";
import { Regolith } from "@regolithjs/regolith";

const app = express();
const port = 3000;

// Create Regolith Regex patterns
const intPattern = new Regolith("^\\d+$");
const floatPattern = new Regolith("^\\d*\\.\\d+$");

console.log("Should be true:", intPattern.test("10"));
console.log("Should be true:", floatPattern.test("10.0"));

console.log("Should be false:", intPattern.test("hello"));
console.log("Should be false:", floatPattern.test("world"));

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});
Enter fullscreen mode Exit fullscreen mode

We added some console.log statements that test different inputs.

When we run this with node index.js, we should see true, true, false, false:

Should be true: true
Should be true: true
Should be false: false
Should be false: false
Example app listening on port 3000
Enter fullscreen mode Exit fullscreen mode

We can trade the logging code with a route, that will allow us to call our backend:

app.get("/check", (req, res) => {
    // Get the input value that we will test
    const value = req.query.value;

    // Run the test with Regolith pattern
    const isInt = intPattern.test(value);
    const isFloat = floatPattern.test(value);

    // Return out test output
    res.json({isInt, isFloat});
});
Enter fullscreen mode Exit fullscreen mode

This will respond when we call the /check route when we give a value like so /check?value=10. When we validate that this works, we can run node index.js and then see the URL (http://localhost:3000/check?value=10) in our browser.

This is what the browser page should look like:

Browser output JSON

The full code after that should look like this:

import express from "express";
import { Regolith } from "@regolithjs/regolith";

const app = express();
const port = 3000;

// Create Regolith Regex patterns
const intPattern = new Regolith("^\\d+$");
const floatPattern = new Regolith("^\\d*\\.\\d+$");

app.get("/check", (req, res) => {
    // Get the input value that we will test
    const value = req.query.value;

    // Run the test with Regolith pattern
    const isInt = intPattern.test(value);
    const isFloat = floatPattern.test(value);

    // Return out test output
    res.json({isInt, isFloat});
});

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});
Enter fullscreen mode Exit fullscreen mode

We can add input validation to check that we provided the value URL parameter:

// Make sure that we provide a `value` in the request
if (!value) {
    return res.status(400).send("Please provide a value query parameter");
}
Enter fullscreen mode Exit fullscreen mode

We can also include the input value in the final output:

res.json({
    value,
    isInt,
    isFloat,
});
Enter fullscreen mode Exit fullscreen mode

The final code should be:

import express from "express";
import { Regolith } from "@regolithjs/regolith";

const app = express();
const port = 3000;

// Create Regolith Regex patterns
const intPattern = new Regolith("^\\d+$");
const floatPattern = new Regolith("^\\d*\\.\\d+$");

app.get("/check", (req, res) => {
    // Get the input value that we will test
    const value = req.query.value;

    // Make sure that we provide a `value` in the request
    if (!value) {
        return res.status(400).send("Please provide a value query parameter");
    }

    // Run the test with Regolith pattern
    const isInt = intPattern.test(value);
    const isFloat = floatPattern.test(value);

    // Return out test output
    res.json({
        value,
        isInt,
        isFloat,
    });
});

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`);
});
Enter fullscreen mode Exit fullscreen mode

We can even test this using the curl command if you have that installed. If not, browser works fine as well.

Check with a float value

curl http://localhost:3000/check?value=10.2
Enter fullscreen mode Exit fullscreen mode

Output from float test

{"value":"10.2","isInt":false,"isFloat":true}
Enter fullscreen mode Exit fullscreen mode

Check with an int value

curl http://localhost:3000/check?value=10
Enter fullscreen mode Exit fullscreen mode

Output from int test

{"value":"10","isInt":true,"isFloat":false}
Enter fullscreen mode Exit fullscreen mode

What are ReDoS attacks?

Regular Expression Denial of Service (ReDoS) attacks occur when vulnerable Regex patterns are executed with specifically constructed inputs that result in an inefficient execution. This can be exploited to cause services to become unavailable because the services are stuck trying to compute the inefficient Regex.

How does Regolith prevent ReDoS attacks?

Regolith prevents ReDoS attacks by disallowing features that make Regex vulnerable to ReDoS attacks. Two of these features are backreferences and look-around, which aren't available in Regolith. When they features are invoked in other Regex libraries, they can take exponentially long to execute, crashing your server and causing a denial of service. We want to prevent this, so we use Regolith, which has a linear worst case time.

Feedback

If you have any feedback or questions, please add a comment here or ask in the Regolith discussion form.

⭐ If you found this article valuable, consider supporting us by giving the Regolith GitHub a star.

Top comments (0)