直接拼接用户输入到mongodb查询极危险,必须白名单字段、禁用$操作符、校验类型与长度;.lean()仅优化返回格式,不提供任何查询安全防护。

直接用用户输入拼接查询对象(比如 { name: req.query.name })是危险的,MongoDB 会执行任意操作符,包括 $where、$regex 注入、甚至通过 $ne 或 $in 触发全表扫描或拒绝服务。必须剥离不可信字段、限制操作符、校验类型。
如何过滤不受信任的查询字段和操作符
用户传来的 req.query 可能包含 {"name": {"$regex": ".*"}, "$where": "sleep(1000)"} —— 这类结构不能原样进 find()。安全做法是白名单字段 + 显式解构,而非深拷贝整个对象。
- 只允许预设字段:如仅
name、status、category可用于查询,其余一律丢弃 - 禁止嵌套操作符:检查每个值是否为 plain object,且 key 是否以
$开头;若发现$regex、$where、$expr等,直接拒绝请求并返回 400 - 字符串值要做 trim 和长度限制(例如
name不超过 64 字符),避免超长正则拖垮查询 - 示例逻辑:
const allowedFields = ['name', 'status', 'category']; const query = {}; for (const key of allowedFields) { if (req.query[key] !== undefined && req.query[key] !== '') { const val = req.query[key]; // 拒绝对象型值(除非明确支持 $in 等有限操作符) if (typeof val === 'object' && !Array.isArray(val)) { if (Object.keys(val).some(k => k.startsWith('$') && !['$in', '$ne'].includes(k))) { throw new Error('Unsafe operator detected'); } } query[key] = val; } }
为什么 .lean() 不解决动态查询的安全问题
.lean() 只影响查询结果的返回形态(从 Mongoose Document 变成 POJO),对查询条件本身毫无防护作用。它既不校验输入,也不拦截恶意操作符,误以为加了 .lean() 就安全,反而会放松警惕。
用于端到端视频本地化流程的轻量编排器,路由至四个专注子技能——/wjs-transcribing-audio、/wjs-translating-subtitles...
-
Model.find(req.query).lean()和Model.find(req.query)在查询阶段行为完全一致,都把原始输入交给了 MongoDB 引擎 -
.lean()的真正价值在后续数据处理:比如你要给每个结果加isInStock属性,这时它才起作用 - 混淆点在于:有人把“动态添加属性”和“动态构造查询”混为一谈,二者安全边界完全不同
如何安全支持有限的动态操作符(如 $in、$ne)
业务确实需要支持多选或排除,但必须收口控制,不能放任自由使用。
- 只接受预定义的操作符:
$in仅允许数组值,且元素类型与字段匹配(如status: { $in: ["active", "pending"] }) -
$ne仅允许字符串/数字/布尔,禁止对象或正则 - 对
$in数组长度设硬上限(如最多 50 项),防止构造超大查询导致 OOM 或慢查询 - 永远不用
$where、$text、$geoNear等高风险操作符,哪怕加了鉴权也不行 - 示例校验:
if (key === '$in' && Array.isArray(val)) { if (val.length > 50) throw new Error('Too many values in $in'); if (val.some(v => typeof v !== 'string' && typeof v !== 'number' && typeof v !== 'boolean')) { throw new Error('$in values must be string/number/boolean'); } }
最易被忽略的一点:即使所有字段和操作符都校验过了,也要确认集合名、数据库名来自配置而非请求参数——动态切换集合名(如 db.collection(req.query.collection))和动态切库(client.db(req.query.db))同样属于高危行为,必须禁用或强白名单控制。










