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:
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With