Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mitigating MongoDB injection attacks with Mongoose

I'm using the Mongoose ODM wrapper for NodeJS and I'm concerned about injection attacks. Let's assume I have the following schema:

const UserSchema = new mongoose.Schema({ userName: String, password: String });

If I were to perform a login request that looks like the following:

router.post('/login', (request, response) => {

    const userName = request.body.userName;
    const password = request.body.password;

    User.findOne({ userName: userName }, function (error, user) {
        // ... check password, other logic
    });
});

I would be open to an injection attack with the following JSON payload which will always find a user:

{
    "email": { "$gte": "" },
    "password": { "$gte": "" }
}

I'm not concerned about the password as it is hashed if a user is found which prevents any actual log in but I want to make sure my input is sanitized so that an attacker wouldn't even make it to that point.

I'm aware of the mongo-sanitize NPM package referenced in a similar StackOverflow post which appears to remove all JSON keys that begin with '$'. I plan on using this anyway but I will never allow the user to submit raw, unparsed JSON. Is it good practice in that case to just call toString() on the userName assuming I do the correct null checks?

const userName = request.body.userName.toString();

That would eliminate the query from being executed but it doesn't feel very secure. I assume the following is a better approach as it tries to convert userName to a String:

User.findOne({ userName: { "$eq": userName } }, function (error, user) {
     // ... other logic
});

I can't find anything concerning this in the in the Model.findOne() documentation which leads me to believe I'm overlooking something.

Any insight would be appreciated.

Other References:

  1. https://blog.websecurify.com/2014/08/hacking-nodejs-and-mongodb.html
  2. https://ckarande.gitbooks.io/owasp-nodegoat-tutorial/content/tutorial/a1_-_sql_and_nosql_injection.html
like image 335
John P. Avatar asked Oct 08 '18 17:10

John P.


2 Answers

While you could use $eq to ensure an equality comparison is used in the query, your express route handler is a better place to perform request format validation.

A valid POST /login should have userName and password string fields in the body of the request. If not, it should be rejected before it even gets to Mongoose.

like image 181
JohnnyHK Avatar answered Oct 13 '22 09:10

JohnnyHK


Additionally, you can use npm package "mongo-sanitize" as given as per their documentation as below:

var sanitize = require('mongo-sanitize');

// The sanitize function will strip out any keys that start with '$' in the input,
// so you can pass it to MongoDB without worrying about malicious users overwriting
// query selectors.
var clean = sanitize(req.params.username);

Users.findOne({ name: clean }, function(err, doc) {
  // ...
});

If sanitize() is passed an object, it will mutate the original object.

like image 1
Jitendra Avatar answered Oct 13 '22 10:10

Jitendra