在Node.js中使用Sequelize ORM时如何防范SQL注入?
Sequelize 防范SQL注入的实操方案(针对你给出的场景)
你当前代码的基础安全属性
你写的where: { id: editInfoId }属于Sequelize的标准参数化查询写法,ORM底层会自动把用户输入的参数和SQL语句做分离,不会直接将用户输入拼接进SQL,本身已经可以抵御绝大多数常规SQL注入攻击。但为了实现更严谨的防护,还需要补充以下操作:
该场景需额外补充的防护措施
- 新增请求参数类型校验
路由中的id为正整数类型,但req.params.id默认取到的是字符串格式,需先做格式校验过滤畸形参数,避免不必要的数据库查询,也能进一步阻断特殊构造的注入尝试:const editInfoId = req.params.id; // 校验是否为正整数 const id = Number(editInfoId); if (isNaN(id) || id <= 0) { return res.status(400).send('参数不合法'); } - 模型字段严格定义类型
给Movie模型的id字段明确定义为数字类型,Sequelize执行查询时会自动做类型转换,不符合类型要求的参数会直接抛出错误,不会进入查询流程:const Movie = sequelize.define('Movie', { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, // 其余字段定义 }); - 禁止使用
Op.raw拼接用户输入
该操作符会直接将内容插入SQL语句,不会做任何转义处理,存在极高注入风险,非必要不要使用,必须使用时要对拼接内容做严格的白名单校验。 - 动态查询做字段白名单过滤
如果你的where条件是动态根据用户传入参数生成的,不要直接把整个请求参数对象作为where值,必须仅保留允许查询的字段:// 错误写法,用户可以传入任意字段作为查询条件 // await Movie.findOne({ where: req.query }) // 正确写法,仅保留允许的字段 const where = { id: id } if (req.query.name) where.name = req.query.name await Movie.findOne({ where }) - 原生查询必须用占位符
如果业务需要用到sequelize.query()执行原生SQL,绝对不要手动拼接用户输入,必须使用ORM提供的占位符做参数绑定:// 错误写法,存在注入风险 // await sequelize.query(`SELECT * FROM movies WHERE id = ${editInfoId}`) // 正确写法,参数化绑定 await sequelize.query(`SELECT * FROM movies WHERE id = ?`, { replacements: [id], type: QueryTypes.SELECT })
修改后的完整代码
albumEdit: async (req, res) => { const editInfoId = req.params.id; // 校验参数合法性 const id = Number(editInfoId); if (isNaN(id) || id <= 0) { return res.status(400).send('无效的资源ID'); } try { const movie = await Movie.findOne({ where: { id: id } }); if (movie) { return res.render('admin/movies/edit', { title: 'Edit Movie On Page One', movie }); } return res.status(404).send('资源不存在'); } catch (err) { console.error('查询失败:', err); return res.status(500).send('服务器内部错误'); } },
内容的提问来源于stack exchange,提问作者freelanceing mindset
相关产品推荐
相关产品推荐

