MongoDB不存在SQL注入,但存在NoSQL注入:用户输入未经校验直接用于查询对象会导致认证绕过、全表扫描等风险;必须对req.body等输入做类型判断、格式校验、拒绝特殊操作符,并禁用$where、严格限制$regex。

直接用 findOne({ username: req.body.username }) 就是高危操作
MongoDB 本身不解析 SQL 字符串,所以没有传统 SQL 注入,但它会原样解释传入的 BSON 对象。一旦你把 req.body.username 这种未经校验的用户输入直接塞进查询对象,攻击者就能提交 {"$ne": null} 或 {"$regex": ".*"},让 findOne() 变成“找任意一个用户”或“全表扫描”。这不是数据库漏洞,是代码把控制权交给了攻击者。
常见错误现象:登录接口输 {"$ne": null} 当用户名、{"$ne": ""} 当密码,直接返回第一个用户,认证逻辑完全失效。
实操建议:
- 永远不要信任
req.body、req.query、req.params的原始值——它们可能是字符串、对象、数组、null,甚至带$操作符的嵌套结构 - 对每个字段做显式类型判断:
typeof req.body.username === 'string'是最低门槛 - 紧接着加格式校验:
/^[a-zA-Z0-9_]{3,20}$/.test(req.body.username)比/^.+$/安全得多 - 拒绝空字符串、
null、undefined、对象、数组——这些都不是合法用户名
$regex 和 $where 是 NoSQL 注入的“特权通道”
这两个操作符自带执行能力:$regex 启动正则引擎,$where 直接执行 JavaScript(已弃用但仍可能启用)。哪怕你前面做了类型检查,只要在查询中放行它们,整套防御就归零。
常见错误现象:搜索接口写成 { name: { $regex: req.query.q } },攻击者填 .* 就全量匹配,填 $(sleep(1000))(若 JS 引擎开启)可触发延时盲注。
实操建议:
- 禁用
$where—— MongoDB 5.0+ 默认禁用,但旧部署或自定义配置可能仍开着,务必确认security.javascriptEnabled: false -
$regex必须配合转义和$options:const escaped = req.query.q.replace(/[.*+?^${}()|[]\]/g, '\$&');,再构造{ name: { $regex: escaped, $options: 'i' } } - 避免让用户控制
$options值,'i'可以,'gmx'不行 - 性能提醒:
$regex不以^开头就无法走索引,滥用等于主动拖慢数据库
Mongoose 并不自动防注入,strict 模式必须显式启用
Mongoose 的 schema 定义只约束写入(save)、不约束查询(find、findOne)。很多开发者误以为用了 Mongoose 就安全了,结果低版本(6.0 以前)默认 strict: false,导致 User.findOne({ username: { "$ne": null } }) 照样执行。
实操建议:
- 升级到 Mongoose 7+,并全局启用严格模式:
mongoose.set('strict', true); - 查询时别偷懒,用
new mongoose.Schema({ username: String }, { strict: true })显式声明 - 对动态字段(如排序、投影)单独处理,别把
req.query.sort直接透传给.sort() - 禁用
allowDiskUse以外的危险选项,尤其避免lean: false+ 复杂聚合时意外触发原型链污染
Java 中用 BasicDBObject 构造查询 ≠ 参数化查询
Java 开发者容易误把 new BasicDBObject("username", new BasicDBObject("$eq", username)) 当作“参数化”,其实这只是手动拼对象,没解决根本问题——如果 username 本身是 {"$ne": null},那最终传给 MongoDB 的还是恶意 BSON。
真正有效的做法是先过滤、再构造:
- 用
String.matches("^[a-zA-Z0-9_]{3,20}$")做白名单校验,不匹配就拒掉请求 - 校验通过后再用
Filters.eq("username", username)(Mongo Java Driver 4.x+)生成安全查询 - 避免手写
BasicDBObject或Document.parse()—— 后者会把 JSON 字符串重新解析,可能触发 DoS 或原型污染 - Spring Data MongoDB 推荐用
@Query注解配合 SpEL 表达式,但必须确保表达式里不拼接原始参数
最易被忽略的一点:防御必须覆盖所有查询入口,包括 find、findOne、updateOne、deleteMany、aggregate。聚合管道里一个未校验的 $match 阶段,危害不亚于登录绕过。


















