Skip to content

Commit

Permalink
Allow replacement of prohibited characters, instead of removing data
Browse files Browse the repository at this point in the history
  • Loading branch information
fiznool committed Jan 13, 2016
1 parent 10d865c commit 3c9e50a
Show file tree
Hide file tree
Showing 3 changed files with 406 additions and 138 deletions.
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,33 @@ var app = express();

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());

// To remove data, use:
app.use(mongoSanitize());

// Or, to replace prohibited characters with _, use:
app.use(mongoSanitize({
replaceWith: '_'
}))

```

## What?

This module removes any keys in objects that begin with a `$` sign from `req.body`, `req.query` or `req.params`.
This module searches for any keys in objects that begin with a `$` sign or contain a `.`, from `req.body`, `req.query` or `req.params`. It can then either:

- completely remove these keys and associated data from the object, or
- replace the prohibited characters with another allowed character.

The behaviour is governed by the passed option, `replaceWith`. Set this option to have the sanitizer replace the prohibited characters with the character passed in.

See the spec file for more examples.

## Why?

Object keys starting with a `$` are _reserved_ for use by MongoDB as operators. Without this sanitization, malicious users could send an object containing a `$` operator, which could change the context of a database operation. Most notorious is the `$where` operator, which can execute arbitrary JavaScript on the database.
Object keys starting with a `$` or containing a `.` are _reserved_ for use by MongoDB as operators. Without this sanitization, malicious users could send an object containing a `$` operator, or including a `.`, which could change the context of a database operation. Most notorious is the `$where` operator, which can execute arbitrary JavaScript on the database.

The best way to prevent this is to sanitize the received data, and remove any offending keys.
The best way to prevent this is to sanitize the received data, and remove any offending keys, or replace the characters with a 'safe' one.

## Credits

Expand Down
55 changes: 39 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,52 @@
'use strict';

var sanitize = function(val) {
if(Array.isArray(val)) {
val.forEach(sanitize);

} else if(val instanceof Object) {
Object.keys(val).forEach(function(key) {
if (/^\$|\./.test(key)) {
delete val[key];
} else {
sanitize(val[key]);
}
});
var TEST_REGEX = /^\$|\./,
REPLACE_REGEX = /^\$|\./g;

var sanitize = function(val, options) {
options = options || {};

var replaceWith = null;
if(!(TEST_REGEX.test(options.replaceWith))) {
replaceWith = options.replaceWith;
}

return val;
var act = function(val) {
if(Array.isArray(val)) {
val.forEach(act);

} else if(val instanceof Object) {
Object.keys(val).forEach(function(key) {
var v = val[key];
var noRecurse = false;

if(TEST_REGEX.test(key)) {
delete val[key];
if(replaceWith) {
val[key.replace(REPLACE_REGEX, replaceWith)] = v;
} else {
noRecurse = true;
}
}

if(!noRecurse) {
act(v);
}

});
}

return val;
};

return act(val);
};

var middleware = function(options) {
options = options || {};

return function(req, res, next) {
['body', 'params', 'query'].forEach(function(k) {
if(req[k]) {
req[k] = sanitize(req[k]);
req[k] = sanitize(req[k], options);
}
});
next();
Expand Down
Loading

0 comments on commit 3c9e50a

Please sign in to comment.