flawopen.com/参考指南/MongoDB NoSQL 注入:输入如何改变查询
MongoDB NoSQL 注入:输入如何改变查询
数据库安全指南
MongoDB 不执行 SQL,因此问题不在于拼接 SQL 字符串。如果应用在需要标量值时接受不可信的嵌套对象,并将其传入 MongoDB 过滤器,就可能产生 NoSQL 注入。这是应用输入校验缺陷,并非 MongoDB 服务器 CVE。
通俗解释:值变成了规则
想象一个表单要求填写姓名,但工作人员却接受了整套归档指令。数据库随后执行这些指令,而不是比较一个姓名。校验字段是否为预期类型,并由应用自行构造查询规则。
信任边界:从请求 JSON 到 MongoDB 过滤器
- 查询过滤器
- BSON 文档,MongoDB 会将其解释为字段比较,并在明确存在时解释为查询运算符。
- 运算符注入
- 应用在原本只应接受单个字面值的位置传入了用户可控的结构。
- 标量校验
- 在输入影响数据库操作前,检查其类型、长度和允许的格式。
- 字段投影
- 由服务器选择返回字段,以限制意外的数据暴露。
故障如何发生
1
端点预期接收标量
API 契约规定 username 是字符串,但 JSON 解析器也能表示字符串、数组、对象、布尔值和 null。
2
应用跳过类型校验
处理程序将解析后的值直接放入服务器创建的过滤器,因此对象仍是查询结构,而不是字面字符串。
3
MongoDB 解释传入的结构
如果嵌套文档含有查询运算符,谓词就可能偏离预期的精确值比较。受影响记录取决于查询以及应用的授权检查。
4
响应决定暴露范围
返回字段和记录数量取决于投影、端点行为和数据库账户权限。这本身不能证明身份验证绕过或整个数据库被访问。
范围与证据
MongoDB 官方驱动指南说明了这一边界:端点将未经验证的 JSON 转为 BSON 并用作过滤器时会出现此问题。本指南展示的是应用层故障,不声称所有 MongoDB 部署都易受攻击,不指认服务器 CVE,也不提供身份验证绕过方法。
Node.js 中的脆弱与加固模式
VULNERABLE — UNVALIDATED VALUE ENTERS FILTER
app.post("/users/lookup", async (req, res, next) => {
try {
// The route expects a string, but req.body.username is untrusted JSON.
const user = await users.findOne({ username: req.body.username });
res.json(user ? { username: user.username } : null);
} catch (error) {
next(error);
}
});
HARDENED — VALIDATE SHAPE, BUILD FILTER, VERIFY HASH
const loginSchema = z.object({
username: z.string().trim().min(1).max(128),
password: z.string().min(1).max(1024)
}).strict();
app.post("/login", async (req, res, next) => {
try {
const parsed = loginSchema.safeParse(req.body);
if (!parsed.success) return res.sendStatus(400);
const { username, password } = parsed.data;
// The application owns the filter key; input supplies only a string value.
const user = await users.findOne(
{ username },
{ projection: { _id: 1, username: 1, passwordHash: 1 } }
);
const passwordMatches = user &&
await argon2.verify(user.passwordHash, password);
if (!passwordMatches) return res.sendStatus(401);
return res.sendStatus(204); // Session creation is application-specific.
} catch (error) {
next(error);
}
});
加固后的流程会在访问数据库前拒绝非字符串字段,不接受客户端提供的过滤器对象,由应用代码构造固定的过滤字段,只返回选定字段,并在查到用户后验证密码哈希。示例假设 z 是 Zod,users 是 MongoDB 集合,argon2 是已配置的密码哈希库;会话创建刻意不在示例范围内。
修复验证清单
- ✓发送普通字符串,并确认处理程序只查询应用明确定义的字段。
- ✓发送对象、数组、数字、布尔值、null、缺失字段、超长字符串和未知属性;确认 schema 在调用 MongoDB 前拒绝无效形状。
- ✓确认数据库调用收到的是服务器构造的过滤器,而不是客户端提供的过滤器或原始 JSON 片段。
- ✓确认投影排除密码哈希及无关字段,并且数据库角色仅拥有必要集合权限。
- ✓使用 Argon2id 或 bcrypt 哈希密码,并在应用中验证哈希;绝不要把提交的密码用作 MongoDB 过滤条件。
一手资料
浏览相关安全指南:打开安全目录 →