Bugwhacker
Bugwhacker

Reputation: 91

Can you tell me if express-mongo-sanitize is working?

I'm trying to set up some security middleware for my humble little MERN web app, and I'm currently using helmet and express-mongo-sanitize, specifically for protection against NoSQL injection attacks.

I've set it up, however, as below in my server.js file:

const express = require('express')
const helmet = require('helmet')
const mongoSanitize = require('express-mongo-sanitize')

...

app.use(mongoSanitize())
app.use(helmet())

// Routes below

...

I've tried to test it by making a mock sign up like:

username: {"$gt": ""} password: 'TestPassword'

so that req.body would be:

{

username: '{"$gt": ""}',

password: 'TestPassword'

}

but express-mongo-sanitize doesn't seem to be catching it and it goes through to my database. Am I misunderstanding something? The value of the username key is a string, so maybe it's already OK? Please forgive my ignorance, I'm learning.

Upvotes: 6

Views: 3995

Answers (5)

dimitris tseggenes
dimitris tseggenes

Reputation: 3186

Read carefully the documentation

This module searches for any keys in objects that begin with a $ sign or contain a ., from req.body, req.query or req.params. It can then either:

  • completely remove these keys and associated data from the object, or
  • replace the prohibited characters with another allowed character.

It searches for KEYS, and NOT values. So in this case

{ username: '{"$gt": ""}', password: 'TestPassword'}

the $ sign exists in the value of username key and not the key itself. That's why express-mongo-sanitize does not catch it.

To understand it better, look at this example

// req.body
{ 
    "username": "{'$gt': ''}", 
    "password": "TestPassword",
    "$ne": "1",
    "$gt": "",
}

// the default implementation of express-mongo-sanitize will remove 
// the last two keys and not the first one.
// So, right after the middleware you will get this 
{ 
    username: "{'$gt': ''}", 
    password: "TestPassword",
}

Upvotes: 1

Tony
Tony

Reputation: 21

Ran into the same problem and what worked for me was parsing the incoming request body before using the mongoSanitize package. Like this...

const express = require("express")
const mongoSanitize = require("express-mongo-sanitize')

const app = express()

app.use(express.json())
app.use(mongoSanitize())

Upvotes: 2

Charlie
Charlie

Reputation: 51

I think the answer by @A10n is correct, and so it appears that 'express-mongo-sanitize' is only a partial solution. I've added my quick-and-dirty solution to remove curly brackets from every req.body/params object (which should blunt most NoSQL attacks) like so:

// Middleware that replaces all {} symbols with [] to prevent NoSQL attack
    const removeCurlies = (req, res, next) => {
      Object.keys(req.body).forEach((key) => {
        req.body[key] = _.replace(req.body[key], "{", "[");
        req.body[key] = _.replace(req.body[key], "}", "]");
      });
      Object.keys(req.params).forEach((key) => {
        req.params[key] = _.replace(req.params[key], "{", "[");
        req.params[key] = _.replace(req.params[key], "}", "]");
      });
      next();
    };

Then, before your routes:

    app.use(removeCurlies);

Upvotes: 0

A10n
A10n

Reputation: 11

From what I understood, from debugging and going through the code, the keys it sanitizes is any potential key in a key=value pair of query & post params that have the $ or a dot. It also tries to sanitize any keys in the body and header of the request.

For example, even the json provided by the previous user above won't do it.

but https://your-domain/?$user=json would be sanitized to user=json.

It doesn't remove $ from the value of the params as you and also I was expecting. I also opened up a question on the github to the creator and will see what he says. I would think the security risk is for both the key and value. This doesn't do any good if you're not saving the key to mongodb but saving the value instead.

For reference it checks the following HTTP sections to remove any potential harmful $ or .

['body', 'params', 'headers', 'query'].forEach(function (key) ...

Upvotes: 1

breaths
breaths

Reputation: 51

What express-mongo-sanitize does is sanitize keys that start with a dollar sign.

username: '{"$gt": ""}' --> this isn't a key starting with a dollar sign. Rather, the value of username is just a string.

Try sending it this object instead:

{

"username": { "$gt": "" }

}

Upvotes: 5

Related Questions