The perennial number 1 on the OWASP Top Ten list is injection. Originally SQL Injection, but nowadays when databases might not be relational, also NoSQL, including the MongoDB used in these materials.
There serious issues with injections are all derived from the program taking the user entered data at face value. First look at the following MongoDB code:
db.user.find().pretty() { "_id" : ObjectId("5e79fd3131f468145cb92c2b"), "email" : "nmla@iba.dk", "__v" : 0, "created" : ISODate("2020-03-24T12:29:37.690Z"), "firstName" : "Niels", "lastName" : "Larsen", "password" : "$2a$10$4qaT09Yyy9CdREncdaGGleA1b7pCjuWj7Do0kF8IZFfab1GXDuo0O" } { "_id" : ObjectId("5ea18bb90cb6c8975e345410"), "email" : "admin@iba.dk", "__v" : 0, "created" : ISODate("2020-04-23T12:36:09.718Z"), "firstName" : "admin", "lastName" : "Adm", "password" : "$2a$10$z.q1y1DtKVpQl9JAjksl7uq.Hyn6e0AX/4dBBqSkm5jbgi0MHENV." } { "_id" : ObjectId("5ea18bf90cb6c8975e345411"), "email" : "doe@iba.dk", "__v" : 0, "created" : ISODate("2020-04-23T12:37:13.799Z"), "firstName" : "anonymous", "lastName" : "Anon", "password" : "$2a$10$6tlgjPflyF0BqA2vYUB3WelLFVmUQjoy7Po1Y1oW1A7wsDKj.KKMu" }
This is a read of all objects in the collection.
Now if we supply a query parameter such as
{email: "nmla@iba.dk"}
we get
db.user.find({email: "nmla@iba.dk"}).pretty() { "_id" : ObjectId("5e79fd3131f468145cb92c2b"), "email" : "nmla@iba.dk", "__v" : 0, "created" : ISODate("2020-03-24T12:29:37.690Z"), "firstName" : "Niels", "lastName" : "Larsen", "password" : "$2a$10$4qaT09Yyy9CdREncdaGGleA1b7pCjuWj7Do0kF8IZFfab1GXDuo0O" }
Let us assume we do not know any users, we could
enter the query param {email: {$ne:""}}
to get
db.user.find({email: {$ne:""}}).pretty() { "_id" : ObjectId("5ea18bb90cb6c8975e345410"), "email" : "admin@iba.dk", "__v" : 0, "created" : ISODate("2020-04-23T12:36:09.718Z"), "firstName" : "admin", "lastName" : "Adm", "password" : "$2a$10$z.q1y1DtKVpQl9JAjksl7uq.Hyn6e0AX/4dBBqSkm5jbgi0MHENV." } { "_id" : ObjectId("5ea18bf90cb6c8975e345411"), "email" : "doe@iba.dk", "__v" : 0, "created" : ISODate("2020-04-23T12:37:13.799Z"), "firstName" : "anonymous", "lastName" : "Anon", "password" : "$2a$10$6tlgjPflyF0BqA2vYUB3WelLFVmUQjoy7Po1Y1oW1A7wsDKj.KKMu" } { "_id" : ObjectId("5e79fd3131f468145cb92c2b"), "email" : "nmla@iba.dk", "__v" : 0, "created" : ISODate("2020-03-24T12:29:37.690Z"), "firstName" : "Niels", "lastName" : "Larsen", "password" : "$2a$10$4qaT09Yyy9CdREncdaGGleA1b7pCjuWj7Do0kF8IZFfab1GXDuo0O" }
Now this is very interesting with a node/Express application in mind. In such a case we might do
User.find(query, null, sort);
Look at the way the query
might be built.
let query = { email: req.body.email };
Whatever collection obj
represents will be
queried with the query parameters held in query
.
The normal way of getting the email address is letting the
user key it into a form and we, the developers get it from
req.body.email
which we use directly to
build out query
object. Thus if the user is
required to key in an email address we build
query = { email: "nmla@iba.dk"}
and we are
at the second example above. But if the devious user enters
{$ne: ""}
or something like that,
we build
query = {email: {$ne: ""}}
This is the cue to solving today's assignment, and indeed to play with challenging Mongo databases.
It goes without saying that any decent test of a web application includes asserting that injection attempts fail. This means sanitizing any user input. Period!