NoSQL注入测试的实操经验分享
渗透测试进阶笔记:NoSQL注入测试怎么做更稳
我第一次认真做 NoSQL 注入测试,不是在靶场,而是在一个“看起来很安全”的内部项目上。接口文档写得漂漂亮亮,开发也拍胸口说都做了过滤,结果我拿登录接口随手试了个 JSON 条件,居然直接把认证逻辑绕过去了。那一刻我真有点头皮发麻:NoSQL 注入最坑的地方,不是 payload 多花哨,而是很多团队压根没把“对象注入”当成注入。
我踩过的一个典型坑
MongoDB 场景里,最常见的不是拼接字符串,而是后端把用户传来的 JSON 原样塞进查询条件。比如本来希望接收:
{"username":"test","password":"123456"}
但如果服务端没有限制类型,我传成:
{"username":{"$ne":null},"password":{"$ne":null}}
查询语义一下就变了。你说它像不像“你问我要钥匙,我直接把整扇门拆了”。
我后来复盘了几次,发现这类问题特别容易出现在 Node.js + Express + MongoDB 的组合里,尤其是直接用 req.body 进查询的代码。开发觉得自己没拼接字符串,就掉以轻心,实际上风险一点没小。
我测试时会盯死这几个入口
真的,不用一上来就全站狂扫,先看最容易出事的地方:
- 登录、找回密码、验证码校验
- 搜索、筛选、分页接口
- 后台按条件导出数据
- 任何支持 JSON 查询或高级过滤的接口
我自己的习惯,是先抓一个正常请求,再把原本的字符串值替换成对象、数组、布尔值、null。如果服务端居然照单全收,那味儿就不对了。
一些很实用的判断信号
- 响应时间突然变长,说明查询逻辑被改了
- 报错里出现
$regex、$where、CastError之类关键词 - 返回结果集明显变大,甚至把本不该出现的数据带出来
- 登录失败提示突然变成 500,这通常比“账号密码错误”更值得高兴
实战里别只会跑 payload
我现在越来越不迷信字典了。NoSQL 注入测试,重点是理解后端怎么接收数据。Content-Type 是 application/json,和 x-www-form-urlencoded,测试方式完全不同。有次我折腾半天没复现,最后发现 WAF 只拦了 URL 参数,JSON 体里塞 $ne 根本没人管,真是又离谱又真实。
很多漏洞不是“防不住”,而是“根本没按那个方向防”。
修复建议我一般会这样提
- 服务端强制字段类型,用户名密码只能是字符串
- 禁止客户端直接传查询操作符,比如
$ne、$gt、$regex - 使用 schema 校验,像 Joi、Zod 这类工具别省
- 高危查询关闭危险表达式能力,别让
$where乱跑 - 日志里保留异常请求样本,复测时特别省时间
有个数据我印象很深:OWASP 这些年一直把注入类问题放在高风险类别里,不是因为它老派,而是它总能换个壳继续出现。SQL 注入老朋友,NoSQL 注入像它那个低调但更阴的表弟。
我最后学到的一件事
NoSQL 注入测试最怕“测了,但没测到数据结构”。只盯特殊字符,基本等于拿体温计修空调。真正有用的,是搞清楚输入有没有从“值”变成“条件”。一旦发生这个转换,后面的事就不太体面了。
下次再有人跟我说“我们这个不是 SQL,所以没注入”,我大概率会先沉默两秒,然后把 Burp 打开。

参与讨论
登录接口用$ne直接绕过去,这也太吓人了😰