首页/安全/漏洞与攻击面速查/NoSQL 注入(MongoDB 场景)
Web 漏洞原理与防护55 条

NoSQL 注入(MongoDB 场景)

MongoDB 等文档数据库在使用查询对象时,若把用户输入整体反序列化为查询条件(可传入 $ne、$gt 等操作符对象),条件逻辑可被篡改、登录校验可被绕过。

漏洞与攻击面速查安全更新于 2026-10-13

NoSQL 注入怎么发生

文档数据库上的注入典型形态是「查询条件被整体反序列化」:后端把客户端提交的 JSON 直接当查询对象传给 MongoDB,攻击者提交 password 为 {"$ne":null} 这类带操作符的值,就能改写条件逻辑、绕过登录校验,或通过 $regex、$where 扩大查询范围。查询操作符本身是正常功能,问题出在用户输入能决定查询结构。

基本信息

主要目标MongoDB 及其 ODM(如 mongoose)
注入载体请求体 JSON、查询串、数组参数
危险操作符$ne、$gt、$in、$regex、$where、$function
可能后果认证绕过、越权查询、正则拒绝服务
修复方向强制类型转换、字段白名单、集合 schema 校验
辅助收敛禁用服务端 JavaScript,关闭或限制 $where
覆盖范围所有把用户输入当查询条件的接口,不只登录

风险写法与安全写法

场景风险写法安全写法
登录校验findOne(req.body)显式取字段并做 String 转换与长度校验
列表筛选把 query 整体传入 find()只接受白名单内的筛选项
关键字搜索用户输入直接进 $regex转义正则元字符并限制长度
聚合统计用户输入拼进 $where禁用服务端脚本,改用普通查询实现
排序分页用户传入 sort 对象映射到固定字段名与固定方向

风险写法与修复

风险写法与修复
// 风险:直接使用客户端 JSON 作为查询条件
// db.collection('users').findOne(req.body)

// 修复:只取所需字段并强制类型
const username = String(req.body.username || '');
const password = String(req.body.password || '');
if (!username || username.length > 64) throw new Error('invalid input');
db.collection('users').findOne({ username, password });

输入层限制(示意)

输入层限制(示意)
拒绝非字符串/数字类型的参数:对象与数组一律拒绝
过滤以 $ 开头的键名,禁止出现在用户可控的字段名里
为集合定义 schema 校验($jsonSchema 或 ODM schema)限制字段类型
禁用服务端 JavaScript 执行,避免 $where、$function 被滥用
正则搜索先转义元字符并限制长度,防止 ReDoS

典型使用场景

  • 新增登录、搜索、导出接口时的代码评审要点
  • 渗透测试报告的整改项复核
  • 从裸驱动迁移到 ODM 时,检查类型校验是否真的生效
  • 老系统加固:禁用服务端脚本、收敛查询字段
  • 日志排查:发现带操作符的用户输入时定位到接口
  • 安全编码培训中作为对象注入的代表案例
ODM 提供 schema 校验时,为集合定义严格 schema 可显著降低此类风险,但校验规则要覆盖全部写入路径,包括脚本导入与数据修复作业。
只在登录接口做类型校验不够:搜索、筛选、导出接口同样可能把用户输入当查询对象,等于留了另一个入口。

易错点

  • 只在登录接口做了类型校验,搜索与筛选接口同样传对象,等于留了另一个入口
  • 用 $where 或服务端 JavaScript 实现复杂查询,把注入面扩大到脚本执行
  • 正则搜索不转义元字符,恶意正则把数据库 CPU 打满
  • 依赖 ODM 的默认行为而不定义 schema,类型限制依然可被绕过
  • 校验只做在前端,后端直接信任请求体,前端校验对攻击者无效

数据来源与参考

  • MongoDB 官方文档(Query and Projection Operators)
  • OWASP NoSQL Injection 说明
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌