The Dark Side: Injecting Javascript variables into MongoDB Queries in Meteor


Let’s take a walk, you and I, and visit the places they tell us not to go.  This is just a short one, but might prove interesting for those that need to know.

Say we’ve got a basic query, let’s say it’s into a Jobs collection, and we want to find a document with a ‘job_dbid’ field of whatever has been passed as a parameter in our url. Further, let’s say that for whatever reason, Mongo is being picky– it wants a string, and not a number. If it just wanted a number, it would be a simple matter of (I’m using iron:router here, so my parameter can be identified by this.params.param so if the param is foo, it’d be: this.params.foo):

Jobs.findOne( {job_dbid: parseInt(this.params.foo) } );

But as a string, it wants to see “foo” in the query. Of course, if we surround this.params.foo in parenthesis, we’re going to query on the literal string, “this.params.foo”. One way to get this done is:

var query = '"' + this.params.foo '"';
Jobs.findOne( { job_dbid: eval(query) } );

Obviously, there’s some serious danger here. Since our url is open to the world, someone looking to misbehave could take an interest in capitalizing on this. So, I’ll leave it to you to sanitize what’s going into eval() as is best for your project, if you choose to go this route. This is a dangerous technique, no doubt about it. But rigorous sanitization can take the sharp pointies out.

Here’s another one. Say we want to find something more along the lines of mySQL’s LIKE. Mongo offers RegEx: $regex. The problem comes in when we want the object of the search to be variable. Here’s another potential use of eval(). Let’s imagine we are using a jQueryUI autocomplete, and we want to feed it from a Mongo Collection. I’m just going to deal with the usage of Mongo Regex in relation to Javascript injected variables, so I’m not going to list all the code for this, just what’s germane to the topic.

With that in mind, let’s agree that whatever the user is entering into the <input> box is coming in to us via request.term. So, we want to match on that:

var arr = [];
var re = '/^' + request.term + '/i';
arr = Jobs.find( { job_name: {$regex: eval(re) } }, { job_name:1, limit:50 } ).fetch();

Another way to explore searching like this:

var arr = [];
var re = '/^' + request.term + '/i';
arr = Jobs.find( { job_name: eval(re) }, { job_name:1, limit:50 } ).fetch();

Remember, trust no one.. or a kinder gentler way to say it: “trust, but verify”. If you chose to use eval() on terms coming in from the wild, sanitize, sanitize, sanitize.

Leave a comment