首页 > 数据库 >Node.js防止MongoDB执行注入式查询的方法

Node.js防止MongoDB执行注入式查询的方法

来源:互联网 2026-07-08 08:45:02

对用户输入进行严格类型与格式校验,禁用$where、$regex等高危操作符,并构建四层纵深防护体系可有效防御MongoDBNoSQL注入。字符串字段须通过typeof与正则双重验证,$regex操作符需转义用户输入,$where应彻底禁用,同时避免依赖黑名单过滤或JSON.parse()二次解析。

MongoDB NoSQL注入防护:从类型校验到纵深防御

MongoDB本身没有SQL注入一说,但应用层如果直接把用户输入塞进查询对象,就会引发NoSQL注入。要防住这个风险,需要对字段做严格的类型与格式校验,禁用$where$regex这类高危操作符,再叠一套四层纵深防护体系——这几步缺一不可。

Node.js防止MongoDB执行注入式查询的方法

长期稳定更新的攒劲资源: >>>点此立即查看<<<

直接传req.bodyfindOne()就是高危操作

把用户输入原封不动塞进findOne()find()updateOne()的第一个参数,等于把查询逻辑的控制权拱手让给攻击者。MongoDB驱动不会做任何解析或拦截,它只管把JavaScript对象序列化成BSON发给服务端——{ "$ne": null }会被照单执行,不是“无效语法”,而是一条合法查询指令。

常见翻车现场:db.users.findOne({ username: req.body.username }),攻击者提交{"$ne": null},直接绕过登录校验;Model.find(req.query.filter),前端传{"status": {"$in": ["active", "deleted"]}}看着还行,但没人拦得住{"$where": "sleep(1000)"}

  • 所有主流驱动(Node.js原生驱动、Mongoose)行为一致:不校验、不重写、不拒绝非法结构
  • Mongoose的strict: true默认只限制写入时的schema外字段,对查询条件完全无感
  • 别信“用了Mongoose就安全”——Model.find(req.body)在任何版本下都等于裸奔

对字符串字段必须做typeof + 正则双校验

username、email、title这类字段,业务上本来就该是纯字符串,那就得用代码把它钉死。类型校验是第一道防线,格式校验是第二道,缺一不可。

  • 先用typeof value === 'string'排除对象、数组、null、undefined
  • 再用正则限定内容范围:/^[a-zA-Z0-9_]{3,20}$//^.+$/安全得多
  • 主动拒绝空字符串和前后空白:value.trim() === ''需单独判断
  • Unicode控制字符、零宽空格、BOM头也要过滤,可用value.replace(/\p{C}/gu, '')清理

示例:

if (typeof req.body.username !== 'string' || !/^[a-zA-Z0-9_]{3,20}$/.test(req.body.username.trim())) {  return res.status(400).json({ error: 'Invalid username' });}

$regex$where$expr必须隔离用户输入

这几个操作符是NoSQL注入的“特权通道”。哪怕前面做了严格的字符串校验,一旦放开它们接收原始输入,整个防御体系就形同虚设。

  • $regex必须配合$options: 'i',且对用户输入做转义:req.query.q.replace(/[.*+^${}()|\[\]\\]/g, '\\$&')
  • $where应彻底禁用——它允许执行任意JavaScript,而且不走索引,性能和安全双崩
  • $expr若必须使用,只能接受白名单内的固定表达式,不能拼接用户输入
  • 不要用JSON.parse()二次解析用户输入——可能触发原型污染或正则DoS

错误写法:{ name: { $regex: req.query.q } };正确写法:

const escaped = req.query.q.replace(/[.*+^${}()|\[\]\\]/g, '\\$&');db.users.find({ name: { $regex: escaped, $options: 'i' } });

别依赖“过滤$符号”或“黑名单操作符”

简单粗暴地删掉$或禁止$ne$gt等关键词,是典型的伪方案。MongoDB会安静忽略无效操作符,导致查询逻辑意外放行数据。

  • 用户输入{"status": {"$ne": "deleted"}},过滤后变成{"status": {"ne": "deleted"}},MongoDB不报错也不匹配,等价于{}——查出全部文档
  • 攻击者可用Unicode编码绕过,比如\u0024ne代替$ne
  • 黑名单永远追不上新操作符,$text$geoWithin$function(MongoDB 4.4+)都是潜在入口

真正有效的做法,是从源头切断恶意结构的传播路径:只允许你明确定义的字段名和值类型进入查询对象,其余一律拒之门外。复杂点在于字段语义各异——搜索字段要支持模糊匹配,ID字段要校验ObjectId格式,时间范围字段要转为Date实例。没有银弹,只有按字段逐个收口。

侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述

热游推荐

更多
湘ICP备2026025700号-3 湘公网安备 43070302000280号
All Rights Reserved
本站为非盈利网站,不接受任何广告。本站所有软件,都由网友
上传,如有侵犯你的版权,请发邮件给xiayx666@163.com
抵制不良色情、反动、暴力游戏。注意自我保护,谨防受骗上当。
适度游戏益脑,沉迷游戏伤身。合理安排时间,享受健康生活。