Node.js中防止用户越权查看修改其他商户停车数据的方法
问题根因
越权漏洞由四个逻辑错误共同导致:
- 关联ID不匹配:
Parking集合的merchantId字段关联的是Merchant集合的文档_id,而JWT中存储的req.data.id是Auth集合的用户主键,二者没有直接映射关系,原有代码中merchantId: req.data.id的条件从一开始就无法匹配正确的所属关系。 - 查询方法误用:
findByIdAndUpdate默认以主键_id作为核心匹配条件,传入包含merchantId的多条件对象时,部分Mongoose版本会直接忽略_id外的其他字段,导致权限过滤逻辑完全不生效。 - 缺失结果校验:
findByIdAndUpdate/findOneAndUpdate未匹配到符合条件的文档时会返回null,原有代码没有判断返回值,无论是否真的完成更新都直接返回成功响应,非法操作也会收到成功提示。 - 缺失账号类型校验:接口没有判断当前登录用户的
accountType,普通用户、服务商账号也能直接发起停车数据修改请求。
修复方案
按照以下逻辑调整即可实现严格权限管控:
- 接口入口先校验登录用户存在,且账号类型为
merchant,非商户账号直接返回403错误 - 通过当前登录用户的Auth ID,查询绑定的Merchant文档,拿到商户主体自身的
_id - 改用
findOneAndUpdate方法,同时传入停车记录ID、当前商户ID两个匹配条件执行更新 - 判断更新操作的返回值,若为
null说明要么停车记录不存在,要么不属于当前商户,直接返回403权限错误 - 停车详情、列表查询接口复用相同的过滤逻辑,查询时始终携带当前商户ID作为过滤条件,避免越权查看
修正后的完整接口代码
exports.updateParking = async (req, res) => { try { const { parkingName, price, address, name, phoneNumber, about } = req.body; const { parkingImage } = req.files; // 校验登录用户身份与账号类型 const currentAuthUser = await Auth.findById(req.data.id); if (!currentAuthUser) return res.status(404).json({ error: "用户不存在" }); if (currentAuthUser.accountType !== "merchant") { return res.status(403).json({ error: "仅商户账号可操作停车数据" }); } // 查询当前账号绑定的商户主体ID const bindMerchant = await Merchant.findOne({ merchantId: req.data.id }); if (!bindMerchant) { return res.status(403).json({ error: "当前账号未绑定商户主体,无操作权限" }); } // 携带商户权限条件执行更新 const updatedParking = await Parking.findOneAndUpdate( { _id: req.params.id, merchantId: bindMerchant._id }, { $set: { parkingName, price, address, name, phoneNumber, about // 其余待更新字段按业务需求补充 } }, { new: true } // 配置后返回更新后的完整文档,不需要可删除 ); // 无匹配文档直接返回权限错误 if (!updatedParking) { return res.status(403).json({ error: "停车数据不存在,或你无权限操作该数据" }); } return res.status(200).json({ success: true, msg: "停车信息更新成功", data: updatedParking }); } catch (error) { return res.status(500).json({ error: error.message }); } };
优化建议
- 可以把「根据Auth用户ID查询绑定商户ID」的逻辑整合到JWT认证中间件中,认证通过后直接将商户ID挂载到
req对象上,避免所有商户接口重复写查询逻辑 - 为
Parking集合的merchantId字段创建普通索引,大幅提升权限校验、关联查询的执行效率 - 所有涉及停车数据的写操作(删除、修改状态等)都要复用上述权限校验逻辑,不要只在更新接口做校验
内容的提问来源于stack exchange,提问作者user19180062
相关产品推荐
相关产品推荐

