NOSQL Injection test on Node.js/Mongoose API - node.js

I'm diving into NoSql injection so I'm trying to hack my db with postman to see if there is any vulnerability. My requests use parameters to query fields as:
User.find({
// name: req.params.name
name: req.query.name
},
function (err, result) {
if (err) {
console.log('Mongoose findUsers name error: ', err);
res.status(505).send({ error: "Internal error." });
return;
}
if (result != null) {
console.log("Mongoose findUsers name: ", result);
res.status(200).send({
message: "Found users :",
data: result
});
} else {
console.log("Mongoose findUsers name: No user found");
res.status(404).send({
message: "No user found."
});
}
});
So I'm trying to pass a name parameter as {"$ne": null} or {"$gt": ""} , so the query will be localhost:5000/api/users?name={"$ne": null}. Though the response I get from the findOne method is not null, it will return an empty array. Does than mean that I'm already protected against NoSql injections and not need to sanitize queries parameters or am I just not using the right value to perform an injection? What other test could I run to try and check properly if nosql injection are possible ?
As always many thanks for your help.
Cheers.

Related

how to using nested populate in node and mongoose

i'm trying populate method in mongoose.
this is my query
await User.findOne({_id: req.params.userId}).populate({ path: 'review' }).then(result=>{
console.log("here" + result)
if(result && result.length != 0){
return res.json({
msg: "all reviews retrieved",
data: result
})
}
else {
return res.json({
msg: "no review found"
})
}
})
and this is the result i'm getting
enter image description here
now i want to get userSender data. anyone who can help me how to populate user data using reviewSender id?
Try this:
User.findOne({_id: req.params.userId}).populate('review').populate('review.reviewSender');

MongoDB: findOne returns null but document exists in collection

I'm trying to send an email and password server-side and check if a document with those values exists (which it does), but when I console log the results from the query it's null.
Here's the document in the users collection:
{
"_id" : ObjectId("580bcf9874ae28934705c0fc"),
"email" : "johndoe#gmail.com",
"password" : "pass"
}
Here's what I'm sending server-side:
{"email":"johndoe#gmail.com","password":"pass"}
Here's my code (updated):
mongo.connect('mongodb://localhost:27017', function (err, db) {
if (err) {
console.log("error: " + err); // logs nothing
} else {
var users = db.collection("users");
var tasks = db.collection("tasks");
app.post("/login", function(req, res) {
var emailRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
var userInDb;
var userEmail = req.body.email;
var userPassword = req.body.password;
console.log(req.body.email); // logs "johndoe#gmail.com"
console.log(req.body.password); // logs "pass"
if (!userEmail || !userPassword) {
return res.sendStatus(403);
} else if ( !emailRegex.test(userEmail)) {
return res.sendStatus(403);
} else {
users.findOne( { "email": userEmail, "password": userPassword }, function(err, results) {
console.log(results); // logs "null"
if(err) {
console.log("error: " + err); // logs nothing
res.sendStatus(403);
} else {
console.log("here"); // logs "here"
res.sendStatus(200);
}
});
}
});
}
});
each time you pass a callback that has an error parameter, it's your responsibility to check if an error was passed, and if so, deal with it.
in your code, you have two such callbacks:
mongo.connect('mongodb://localhost:27017', function (err, db)
users.findOne( { "email": userEmail, "password": userPassword }, function(err, results)
either one of them can return an error object that might explain the issue.
add the following to the first line of each callback:
if (err) {
return console.log("error: " + err);
}
This one worked for me.
I had to call toArray() method.
I don't remember how I found that solution, cuz in MongoDB manuals they don't call to array method
users.findOne( { "email": userEmail, "password": userPassword }).toArray()
I faced a simular problem in one of my project. It is all because I stored the collection and the document in a database which is different from which my app is connected to. Check that once.
It is really mysterious, I think MongoDB client should make a fix on it.
MongoDB is not very reliable. Often get lose connection in 1/10 of requests. But the very annoying is, it returns an empty array instead of an error in connection, that makes us impossible to catch connection error.
Because I use the existence of documents in DB to reinitialize the project, I really get annoyed of it. CouchDB will not have this problem.
users.findOne({'email' : userEmail , 'password':userPassword }, function(err, result) {
console.log("result:"+result);
});

Why is my Model.find returning nothing?

I'm very new to node and sequelize and I'm trying to follow this short introduction.
I've worked through the parts to connect to my database (postgres). I've also defined a model:
var User = sequelize.define('User', {
username: Sequelize.STRING,
password: Sequelize.STRING
});
I have succesfully synchronized the scheme and created instances. But when I attempt to read from the database using this:
User
.find({ where: { username: 'john-doe' } })
.then(function(err, johnDoe) {
if (!johnDoe) {
console.log('No user with the username "john-doe" has been found.');
} else {
console.log('Hello ' + johnDoe.username + '!');
console.log('All attributes of john:', johnDoe.get());
}
});
That instance does exist, but I only ever see the 'No user with...' message. The query it generates seems correct and when I try it manually, the returned results are what I would expect to see.
Using the same query I can do this, which also works:
sequelize.query("SELECT * FROM my_user_table where username='john-doe'", { type: sequelize.QueryTypes.SELECT})
.then(function(items) {
// We don't need spread here, since only the results will be returned for select queries
console.log(items);
});
What am I missing here?
You're mixing up promises and node-style callbacks. Typically you only expect (err, results) when you pass a callback to the original function. If you call then, you are working with promises and should only expect results. You should call catch to get any errors.
User
.find({ where: { username: 'john-doe' } })
.then(function(johnDoe) {
if (!johnDoe) {
console.log('No user with the username "john-doe" has been found.');
} else {
console.log('Hello ' + johnDoe.username + '!');
console.log('All attributes of john:', johnDoe.get());
}
})
.catch(function(err) {
// Error handling here
});
Actually, you was too close. But you must not use an argument for error handling on then method.
So you must use like the following;
User
.findOne({ where: { username: 'john-doe' } })
.then(function(johnDoe) {
if (!johnDoe) {
console.log('No user with the username "john-doe" has been found.');
} else {
console.log('Hello ' + johnDoe.username + '!');
console.log('All attributes of john:', johnDoe.get());
}
});

Calling stored procedures in Sequelize.js

I have searched documentation and tried google that, but I did not find a straight answer to the question:
How can I call a stored procedure in Sequelize?
I have searched the documentation of Sequelize but I have even not found a trace of the word "procedure" in that.
The closest I got was this bug-report-turned-feature-request:
https://github.com/sequelize/sequelize/issues/959
Quoting from the link:
What I imagine would be awesome:
sequelize.query('CALL calculateFees();').success(
function (settingName1, settingName2, settingName3, users) {
});
They mention that it is possible to call stored procedures, but the syntax is not provided.
Can anyone give me an example with the proper syntax?
Thanks.
Call SP with parameters in Sequelize
sequelize
.query('CALL login (:email, :pwd, :device)',
{replacements: { email: "me#jsbot.io", pwd: 'pwd', device: 'android', }})
.then(v=>console.log(v));
Change success to spread and you're good to go. Note that this will only work on sequlize 2.0
sequalise queries return promises so below is how i query stored procedures.
sequelize.query('CALL calculateFees();').then(function(response){
res.json(response);
}).error(function(err){
res.json(err);
});
I am sure, you may also need to get output from stored procedure. Here is a code including output value from procedure, using sequelize:
models.sequelize.query('DECLARE #outParam1 INT, #outParam2 INT EXEC procedureName #param1=:param, #outParam1 = #outParam1 output, #outParam2 = #outParam2 output SELECT #outParam1 AS "outParam1", #outParam2 AS "outParam2"',
{
replacements:
{
param: 123
},
type: models.sequelize.QueryTypes.EXEC
}).spread(result => {
if (result)
{
console.log("\nInside result : " + JSON.stringify(result));
//return response here
}
For a MSSQL stored procedure accepting two DATETIME parameters, this worked for me:
db.query('EXEC STORED_PROCEDURE_NAME :startDate, :endDate',
{ replacements: { startDate: moment(payload.startDate).format('YYYY-MM-DD HH:mm:ss'), endDate: moment(payload.endDate).format('YYYY-MM-DD HH:mm:ss')},
raw: true }
)
I executed the stored procedure with the EXEC Key word.
sequelize
.query('EXEC getData :#param1', { replacements: { #param1: 'Test'}, type:sequelize.QueryTypes.SELECT })
.then(data => /*Do something with the data*/)
.catch(error => /*Do something with the error*/)
Call SP with multiple parameters in Sequelize
I am using await also.
const existing = await db.sequelize.query(`exec Fetch_Details ${AlphaCode},${Id}`, { type: QueryTypes.SELECT });
if (existing.length>=0) {
res.send({
status: "OK",
message: "Records found!",
result: existing,
});
}
else{
res.send({
status: 404,
message: "Not Found!"
});
}

Pre-populating documents using Mongoose + Express

I am new to Node+Mongoose, and am currently in the process of creating an API using KeystoneJS. I've managed to populate all posts with the author's email and name. My question is, is there a way to populate the post with author everytime, possibly with some middlewear, without having to rewrite it in each method where I retrieve posts? My goal is to not have multiple instances of populate('author', 'email name') scattered throughout the code. For instance, in the future, I'd like to include the author's profile photo url as well, and I'd prefer to be able to make that change in a single place, that will then be reflected in every place that I retrieve posts.
Current implementation:
Post.model.find().populate('author', 'email name').exec(function (err, posts) {
if (!err) {
return res.json(posts);
} else {
return res.status(500).send("Error:<br><br>" + JSON.stringify(err));
}
});
Post.model.findById(req.params.id).populate('author', 'email name').exec(function (err, post) {
if(!err) {
if (post) {
return res.json(post);
} else {
return res.json({ error: 'Not found' });
}
} else {
return res.status(500).send("Error:<br><br>" + JSON.stringify(err));
}
});
You can create model using statics. This is example of methods for schema
PostSchema.statics = {
getAll: function(cb) {
return this
.find()
.populate('author', 'email name')
.exec(cb);
}
}
You still should use "populate", but it will be in schema file, so you will not care about it in future

Resources