【问题标题】:JavaScript NoSQL Injection prevention in MongoDBMongoDB 中的 JavaScript NoSQL 注入预防
【发布时间】:2012-11-06 08:26:30
【问题描述】:

如何防止 JavaScript NoSQL 注入 MongoDB?

我正在开发一个 Node.js 应用程序,并且我正在将一个 json 对象 req.body 传递给 mongoose 模型的保存函数。我以为幕后有保护措施,但事实并非如此。

【问题讨论】:

  • 只要您使用JSON.parse(而不是eval)解析JSON,并且您正在验证数据,您应该没问题。 JSON 本身并不危险 :)
  • 不要阻止东西进入你的数据库,阻止你数据库中的东西作为代码运行。
  • 那么我该如何解析我的帖子对象呢?
  • 我的代码如下所示:module.exports.create = (post, cb) -> post.created_at = Date.now() PostModel(post).save (err, post) -> cb (错误,帖子)
  • PostModel(JSON.parse(post)).save 给出错误 - Unexpected token o

标签: javascript node.js mongodb mongoose javascript-injection


【解决方案1】:

注意 我的回答不正确。请参考其他答案。

--

当客户端程序在 MongoDB 中组装查询时,它会构建一个 BSON 对象, 不是字符串。因此,传统的 SQL 注入攻击不是问题。

详情请关注documentation

更新

避免像eval这样可以执行任意JS的表达式。如果您从用户那里获取输入并运行eval 之类的表达式而不清理输入,您可能会搞砸。正如JoBu1324所指出的,wheremapReducegroup等操作允许直接执行JS表达式。

【讨论】:

  • 我会添加一个“但是,请注意 JavaScript 注入!”答案。阅读media.blackhat.com/bh-us-11/Sullivan/…
  • 考虑到docs 中的node.js 标记和javascript 小节,这个答案是否错误?我现在正在自己寻找这个问题的答案。
  • @JoBu1324 我已经更新了答案。感谢您改进答案:)
  • 请不要破坏您的答案。
  • @FINDarkside 同意。我的回答不正确。已更新。
【解决方案2】:

虽然帖子已经过时,但我正在回答。

我知道三种方法。

首先:有一个多用途的content-filter。还通过过滤的方式提供MongoDB注入保护。

第二个: mongo-sanitize,帮助清理 mongodb 查询以防止查询选择器注入。

第三: 我见过over here 这个解决方案也可以应用于 MongoDB。实现起来真的很简单。仅使用 JavaScript 内置的escape() 函数。

escape() 将字符串转换为ascii 代码。 $ne 转换为 %24ne

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

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

【讨论】:

    【解决方案3】:

    Sushant 的回答不正确。需要了解 MongoDB 中的 NoSQL 注入。

    示例(取自here

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

    如果req.params.password{ $ne: 1 },则在不知道密码的情况下检索用户($ne表示不等于1)。

    MongoDB 驱动程序

    你可以使用mongo-sanitize:

    它会去掉输入中所有以“$”开头的键,所以你 可以将其传递给 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); 
    

    猫鼬司机

    由于它遵循一个模式,如果密码是一个字符串字段,它会将对象{ $ne: 1 }转换为字符串,不会造成任何损坏。在这种情况下,您无需进行清理,只需记住设置适当的架构即可。

    【讨论】:

    • 我刚刚用req.params.password='{ $ne: 1 }' 尝试过这个并没有得到结果,你确定字符串req.params.password 已经解析了它的json 内容吗?
    • @MohammadAli 不,不会自动解析 JSON。问题是当您收到对象{ $ne: 1 } 而不是字符串'{ $ne: 1 }' 时。我已经在我的博客中写了更多详细信息:link
    • 答案中应该提到吗?正如您所写的关于 mongoose 驱动程序的内容也适用于本机 mongodb 驱动程序。而且你也忽略了类型需要是一个对象才能工作的例子
    • @MohammadAli 答案中已经提到过。我说过If req.params.password is { $ne: 1 }。 JavaScript 中的{ $ne: 1 } 代表一个对象而不是字符串。关于 Mongoose,我说过它会将对象转换为字符串。最后强调了:it will convert the object { $ne: 1 } to string
    • 使用猫鼬时,是否可以在 .pre('save') 函数中执行此操作?还是到那时为时已晚?
    【解决方案4】:

    为了防止来自结构未知的数据对象的查询选择器注入

    使用 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)
    }
    

    例如 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 } }
    

    使用deepSanitize(req.query) 净化过的对象(包括嵌套的)会发生变异:

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

    使用{...req.query} 消除对象突变:

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

    【讨论】:

      猜你喜欢
      • 2016-11-04
      • 1970-01-01
      • 1970-01-01
      • 2011-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-03
      相关资源
      最近更新 更多