Socket
Socket
Sign inDemoInstall

express-mongo-sanitize

Package Overview
Dependencies
0
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.1.0 to 1.2.0

6

CHANGELOG.md

@@ -5,2 +5,7 @@ # Change Log

## [1.2.0] - 2016-01-13
### Added
- A new option `replaceWith` which can be used to replace offending characters in a key. This is an alternative to removing the data from the payload.
## [1.1.0] - 2016-01-13

@@ -14,2 +19,3 @@ ### Added

[1.2.0]: https://github.com/fiznool/express-mongo-sanitize/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/fiznool/express-mongo-sanitize/compare/v1.0.0...v1.1.0

53

index.js
'use strict';
var sanitize = function(val) {
if(Array.isArray(val)) {
val.forEach(sanitize);
var TEST_REGEX = /^\$|\./,
REPLACE_REGEX = /^\$|\./g;
} else if(val instanceof Object) {
Object.keys(val).forEach(function(key) {
if (/^\$|\./.test(key)) {
delete val[key];
} else {
sanitize(val[key]);
}
});
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);
}

@@ -28,0 +51,0 @@ });

{
"name": "express-mongo-sanitize",
"version": "1.1.0",
"version": "1.2.0",
"description": "Sanitize your express payload to prevent MongoDB operator injection.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -24,4 +24,11 @@ # Express Mongoose Sanitize

app.use(bodyParser.json());
// To remove data, use:
app.use(mongoSanitize());
// Or, to replace prohibited characters with _, use:
app.use(mongoSanitize({
replaceWith: '_'
}))
```

@@ -31,9 +38,16 @@

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.

@@ -40,0 +54,0 @@ ## Credits

@@ -9,121 +9,361 @@ 'use strict';

describe('Express Mongo Sanitize', function() {
var app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(sanitize());
describe('Remove Data', function() {
var app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(sanitize());
app.post('/body', function(req, res){
res.status(200).json({
body: req.body
app.post('/body', function(req, res){
res.status(200).json({
body: req.body
});
});
});
app.get('/query', function(req, res){
res.status(200).json({
query: req.query
app.get('/query', function(req, res){
res.status(200).json({
query: req.query
});
});
});
describe('Top-level object', function() {
it('should sanitize the query string', function(done) {
request(app)
.get('/query?q=search&$where=malicious&dotted.data=some_data')
.set('Accept', 'application/json')
.expect(200, {
query: {
q: 'search'
}
}, done);
});
describe('Top-level object', function() {
it('should sanitize the query string', function(done) {
request(app)
.get('/query?q=search&$where=malicious&dotted.data=some_data')
.set('Accept', 'application/json')
.expect(200, {
query: {
q: 'search'
}
}, done);
});
it('should sanitize a JSON body', function(done) {
request(app)
.post('/body')
.send({
q: 'search',
is: true,
and: 1,
even: null,
stop: undefined,
$where: 'malicious',
'dotted.data': 'some_data'
})
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect(200, {
body: {
it('should sanitize a JSON body', function(done) {
request(app)
.post('/body')
.send({
q: 'search',
is: true,
and: 1,
even: null
}
}, done);
even: null,
stop: undefined,
$where: 'malicious',
'dotted.data': 'some_data'
})
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect(200, {
body: {
q: 'search',
is: true,
and: 1,
even: null
}
}, done);
});
it('should sanitize a form url-encoded body', function(done) {
request(app)
.post('/body')
.send('q=search&$where=malicious&dotted.data=some_data')
.set('Content-Type', 'application/x-www-form-urlencoded')
.set('Accept', 'application/json')
.expect(200, {
body: {
q: 'search'
}
}, done);
});
});
it('should sanitize a form url-encoded body', function(done) {
request(app)
.post('/body')
.send('q=search&$where=malicious&dotted.data=some_data')
.set('Content-Type', 'application/x-www-form-urlencoded')
.set('Accept', 'application/json')
.expect(200, {
body: {
q: 'search'
}
}, done);
describe('Nested Object', function() {
it('should sanitize a nested object in the query string', function(done) {
request(app)
.get('/query?username[$gt]=foo&username[dotted.data]=some_data')
.set('Accept', 'application/json')
.expect(200, {
query: {
username: {}
}
}, done);
});
it('should sanitize a nested object in a JSON body', function(done) {
request(app)
.post('/body')
.send({
username: {
$gt: 'foo',
'dotted.data': 'some_data'
}
})
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: {}
}
}, done);
});
it('should sanitize a nested object in a form url-encoded body', function(done) {
request(app)
.post('/body')
.send('username[$gt]=foo&username[dotted.data]=some_data')
.set('Content-Type', 'application/x-www-form-urlencoded')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: {}
}
}, done);
});
});
describe('Nested Object inside an Array', function() {
it('should sanitize a nested object in the query string', function(done) {
request(app)
.get('/query?username[0][$gt]=foo&username[0][dotted.data]=some_data')
.set('Accept', 'application/json')
.expect(200, {
query: {
username: [{}]
}
}, done);
});
it('should sanitize a nested object in a JSON body', function(done) {
request(app)
.post('/body')
.send({
username: [{
$gt: 'foo',
'dotted.data': 'some_data'
}]
})
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: [{}]
}
}, done);
});
it('should sanitize a nested object in a form url-encoded body', function(done) {
request(app)
.post('/body')
.send('username[0][$gt]=foo&username[0][dotted.data]=some_data')
.set('Content-Type', 'application/x-www-form-urlencoded')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: [{}]
}
}, done);
});
});
});
describe('Nested Object', function() {
it('should sanitize a nested object in the query string', function(done) {
request(app)
.get('/query?username[$gt]=foo&username[dotted.data]=some_data')
.set('Accept', 'application/json')
.expect(200, {
query: {
username: {}
}
}, done);
describe('Preserve Data', function() {
var app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(sanitize({
replaceWith: '_'
}));
app.post('/body', function(req, res){
res.status(200).json({
body: req.body
});
});
it('should sanitize a nested object in a JSON body', function(done) {
request(app)
.post('/body')
.send({
username: {
$gt: 'foo',
app.get('/query', function(req, res){
res.status(200).json({
query: req.query
});
});
describe('Top-level object', function() {
it('should sanitize the query string', function(done) {
request(app)
.get('/query?q=search&$where=malicious&dotted.data=some_data')
.set('Accept', 'application/json')
.expect(200, {
query: {
q: 'search',
_where: 'malicious',
dotted_data: 'some_data'
}
}, done);
});
it('should sanitize a JSON body', function(done) {
request(app)
.post('/body')
.send({
q: 'search',
is: true,
and: 1,
even: null,
stop: undefined,
$where: 'malicious',
'dotted.data': 'some_data'
}
})
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: {}
}
}, done);
})
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect(200, {
body: {
q: 'search',
is: true,
and: 1,
even: null,
_where: 'malicious',
dotted_data: 'some_data'
}
}, done);
});
it('should sanitize a form url-encoded body', function(done) {
request(app)
.post('/body')
.send('q=search&$where=malicious&dotted.data=some_data')
.set('Content-Type', 'application/x-www-form-urlencoded')
.set('Accept', 'application/json')
.expect(200, {
body: {
q: 'search',
_where: 'malicious',
dotted_data: 'some_data'
}
}, done);
});
});
it('should sanitize a nested object in a form url-encoded body', function(done) {
request(app)
.post('/body')
.send('username[$gt]=foo&username[dotted.data]=some_data')
.set('Content-Type', 'application/x-www-form-urlencoded')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: {}
}
}, done);
describe('Nested Object', function() {
it('should sanitize a nested object in the query string', function(done) {
request(app)
.get('/query?username[$gt]=foo&username[dotted.data]=some_data')
.set('Accept', 'application/json')
.expect(200, {
query: {
username: {
_gt: 'foo',
dotted_data: 'some_data'
}
}
}, done);
});
it('should sanitize a nested object in a JSON body', function(done) {
request(app)
.post('/body')
.send({
username: {
$gt: 'foo',
'dotted.data': 'some_data'
}
})
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: {
_gt: 'foo',
dotted_data: 'some_data'
}
}
}, done);
});
it('should sanitize a nested object in a form url-encoded body', function(done) {
request(app)
.post('/body')
.send('username[$gt]=foo&username[dotted.data]=some_data')
.set('Content-Type', 'application/x-www-form-urlencoded')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: {
_gt: 'foo',
dotted_data: 'some_data'
}
}
}, done);
});
});
describe('Nested Object inside an Array', function() {
it('should sanitize a nested object in the query string', function(done) {
request(app)
.get('/query?username[0][$gt]=foo&username[0][dotted.data]=some_data')
.set('Accept', 'application/json')
.expect(200, {
query: {
username: [{
_gt: 'foo',
dotted_data: 'some_data'
}]
}
}, done);
});
it('should sanitize a nested object in a JSON body', function(done) {
request(app)
.post('/body')
.send({
username: [{
$gt: 'foo',
'dotted.data': 'some_data'
}]
})
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: [{
_gt: 'foo',
dotted_data: 'some_data'
}]
}
}, done);
});
it('should sanitize a nested object in a form url-encoded body', function(done) {
request(app)
.post('/body')
.send('username[0][$gt]=foo&username[0][dotted.data]=some_data')
.set('Content-Type', 'application/x-www-form-urlencoded')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: [{
_gt: 'foo',
dotted_data: 'some_data'
}]
}
}, done);
});
});
});
describe('Nested Object inside an Array', function() {
it('should sanitize a nested object in the query string', function(done) {
request(app)
.get('/query?username[0][$gt]=foo&username[0][dotted.data]=some_data')
describe('Preserve Data: prohibited characters', function() {
it('should not allow data to be replaced with a `$`', function(done) {
var app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(sanitize({
replaceWith: '$'
}));
app.get('/query', function(req, res){
res.status(200).json({
query: req.query
});
});
request(app)
.get('/query?q=search&$where=malicious&dotted.data=some_data')
.set('Accept', 'application/json')
.expect(200, {
query: {
username: [{}]
q: 'search'
}

@@ -133,29 +373,20 @@ }, done);

it('should sanitize a nested object in a JSON body', function(done) {
request(app)
.post('/body')
.send({
username: [{
$gt: 'foo',
'dotted.data': 'some_data'
}]
})
.set('Content-Type', 'application/json')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: [{}]
}
}, done);
});
it('should not allow data to be replaced with a `.`', function(done) {
var app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(sanitize({
replaceWith: '.'
}));
it('should sanitize a nested object in a form url-encoded body', function(done) {
request(app)
.post('/body')
.send('username[0][$gt]=foo&username[0][dotted.data]=some_data')
.set('Content-Type', 'application/x-www-form-urlencoded')
app.get('/query', function(req, res){
res.status(200).json({
query: req.query
});
});
request(app)
.get('/query?q=search&$where=malicious&dotted.data=some_data')
.set('Accept', 'application/json')
.expect(200, {
body: {
username: [{}]
query: {
q: 'search'
}

@@ -162,0 +393,0 @@ }, done);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc