简体   繁体   English

JavaScript NoSQL 注射预防 MongoDB

[英]JavaScript NoSQL Injection prevention in MongoDB

How can I prevent JavaScript NoSQL injections into MongoDB?如何防止 JavaScript NoSQL 注入 MongoDB?

I am working on a Node.js application and I am passing req.body , which is a json object, into the mongoose model's save function. I thought there were safeguards behind the scenes, but this doesn't appear to be the case.我正在处理一个 Node.js 应用程序,我正在将req.body传递到 mongoose 模型的保存 function 中,这是一个 json object。我认为幕后有保护措施,但事实并非如此。

Sushant 's answer is not correct. Sushant的答案不正确。 You need to be aware of NoSQL injection in MongoDB. 需要了解MongoDB中的NoSQL注入。

Example (taken from here ) 示例 (从此处获取

User.findOne({
    "name" : req.params.name, 
    "password" : req.params.password
}, callback); 

If req.params.password is { $ne: 1 } , the user will be retrieved without knowing the password ( $ne means not equals 1 ). 如果req.params.password{ $ne: 1 } ,则将在不知道密码的情况下检索用户( $ne表示不等于1 )。

MongoDB Driver MongoDB驱动程序

You can use mongo-sanitize : 您可以使用mongo-sanitize

It will strip out any keys that start with '$' in the input, so you can pass it to MongoDB without worrying about malicious users overwriting. 它将去除输入中以“ $”开头的所有键,因此您可以将其传递给MongoDB,而不必担心恶意用户覆盖。

var sanitize = require('mongo-sanitize');

var name = sanitize(req.params.name);
var password = sanitize(req.params.password);

User.findOne({
    "name" : name, 
    "password" : password
}, callback); 

Mongoose Driver 猫鼬司机

As it follows a schema, if the password is a string field, it will convert the object { $ne: 1 } to string and no damage will be done. 在遵循模式时,如果密码是字符串字段,它将把对象{ $ne: 1 }为字符串,并且不会造成任何损坏。 In this case, you don't need to sanitize, just remember to set a proper schema. 在这种情况下,您无需清理,只需记住设置适当的架构即可。

Although the post is obsolete, I'm answering. 尽管该帖子已过时,但我正在回答。

I know three ways. 我知道三种方式。

First: There is a multipurpose content-filter . 首先:有一个多功能的内容过滤器 Also provides MongoDB injection protection by filtering way. 还通过过滤方式提供MongoDB注入保护。

Second: mongo-sanitize , Helper to sanitize mongodb queries against query selector injections. 第二个: mongo-sanitize ,帮助程序针对查询选择器注入清理mongodb查询。

Third: I'd seen over here this solution which can be applied for MongoDB too. 第三:在这里看到可以用于MongoDB的此解决方案。 It's really simple to implement. 实现起来真的很简单。 Only use built-in escape() function of JavaScript. 仅使用JavaScript的内置escape()函数。

escape() converts the string into ascii code. escape()将字符串转换为ascii代码。 $ne is converted into %24ne . $ne转换为%24ne

var privateKey = escape(req.params.privateKey);

App.findOne({ key: privateKey }, function (err, app) {
  //do something here
}

Note My answer is incorrect. 注意我的答案不正确。 Please refer to other answers. 请参考其他答案。

-- -

As a client program assembles a query in MongoDB, it builds a BSON object, not a string. 客户端程序在MongoDB中组装查询时,将构建BSON对象而不是字符串。 Thus traditional SQL injection attacks are not a problem. 因此,传统的SQL注入攻击不是问题。

For details follow the documentation 有关详细信息,请遵循文档

UPDATE 更新

Avoid expression like eval which can execute arbitrary JS. 避免像eval这样的表达式可以执行任意JS。 If you are taking input from user and running eval like expressions without cleaning the input you can screw up. 如果要从用户那里获取输入并运行类似eval表达式而不清除输入,则可能会搞砸。 As pointed by JoBu1324, operations like where , mapReduce and group permit to execute JS expressions directly. 如JoBu1324所指出的,诸如wheremapReducegroup允许直接执行JS表达式。

In order to guard against query selector injections from a data object with unknown structure 为了防止来自结构未知的数据对象的查询选择器注入

Use mongo-sanitize to deeply sanitize via recursion: 使用mongo-sanitize通过递归进行深度消毒:

const deepSanitize = (value) => {
    if(Array.isArray(value)){
        value.forEach(elm=>deepSanitize(elm))
    }
    if(typeof(value) === 'object' && value !== null){
        Object.values(value).forEach((elm)=>{
            deepSanitize(elm)
        })
    }
    return sanitize(value)
}

For example with sanitize(req.query) nested query selectors will not be removed: 例如,使用sanitize(req.query)嵌套查询选择器不会被删除:

const req = {} 
req.query = { _id : { $ne: 1 } } 

console.log(req.query))               // { _id: { '$ne': 1 } }
console.log(sanitize(req.query))      // { _id: { '$ne': 1 } }

Using deepSanitize(req.query) sanitized objects (including nested) are mutated: 使用deepSanitize(req.query)清理对象(包括嵌套对象)是deepSanitize(req.query)

console.log(deepSanitize(req.query))       // { _id: {} }
console.log(req.query)                     // { _id: {} }

Eliminate object mutation with {...req.query} : {...req.query}消除对象变异:

console.log(deepSanitize({...req.query}))  // { _id: {} }
console.log(req.query)                     // { _id: { '$ne': 1 } }

If you are using Mongoose in Mongoose 6 they introduced the sanitizeFilter option that could be used as follows (from the their documentation):如果您在 Mongoose 中使用Mongoose Mongoose 6他们引入了sanitizeFilter选项,可以按如下方式使用(来自他们的文档):

const obj = { username: 'val', pwd: { $ne: null } };
sanitizeFilter(obj);
obj; // { username: 'val', pwd: { $eq: { $ne: null } } });

Sanitizes query filters against query selector injection attacks by wrapping any nested objects that have a property whose name starts with $ in a $eq.通过将任何具有名称以 $ 开头的属性的嵌套对象包装在 $eq 中,来净化查询过滤器以防止查询选择器注入攻击。

You can also set it up to be sensitized by default:您还可以将其设置为默认敏感:

mongoose.set('sanitizeFilter', true);

And you can also skip the default sensitizing by using trusted() :您还可以使用trusted()跳过默认的敏感化:

const user = await User.findOne({
  // Tell Mongoose to not sanitize `{ $ne: true }`
  deleted: mongoose.trusted({ $ne: true }),
  email: req.body.email,
  hashedPassword: req.body.hashedPassword
}).setOptions({ sanitizeFilter: true }); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM