用ORM就真的不会SQL注入了吗?

迷人的志红 阅读 32

我最近在用 Sequelize 写接口,听说 ORM 能防 SQL 注入,但心里还是不踏实。比如下面这种写法:

const user = await User.findOne({
  where: { id: req.query.id }
});

如果用户传了个 '1 OR 1=1 --' 进来,会不会被拼成恶意 SQL?我看文档说参数会自动转义,但不确定是不是所有情况都安全,特别是用 sequelize.literal() 或者 raw query 的时候。

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
 ___晓娜
直接说结论:Sequelize的findOne这种写法是安全的,参数会自动转义,'1 OR 1=1 --' 传进去也不会有问题。

但你担心是对的,ORM防注入是有前提的:

第一种情况,用普通的查询方法比如findOne、findAll、create这些,Sequelize会自动用参数化查询,底层用的是PDO的预处理语句,你完全不用担心。

第二种情况就比较坑了——用sequelize.literal()或者直接写raw query。比如这样:

const user = await User.findOne({
where: sequelize.literal(id = ${req.query.id})
});

这就相当于直接拼接字符串了,用户传什么你就执行什么,OR 1=1 分分钟教你做人。

还有这种:

const [results] = await sequelize.query(SELECT * FROM users WHERE id = ${req.query.id});

同样危险。

正确的做法是:如果非要用literal,参数得自己手动转义,或者用sequelize.escape()。但更推荐的是尽量别用literal,需要动态字段的话用sequelize.where()和sequelize.fn()。

至于raw query,要用占位符:

const [results] = await sequelize.query(
'SELECT * FROM users WHERE id = :id',
{
replacements: { id: req.query.id }
}
);

这样Sequelize会自动处理转义。

总结一下:ORM不是万能的,用对了方法就很安全,但一旦用了literal或者自己拼字符串,就得自己负责防注入了。官方文档里也明确说了,literal的值不会被转义,需要开发者自己保证安全。
点赞
2026-03-19 20:09
シ雯婷
シ雯婷 Lv1
别被 ORM 的宣传忽悠了,它只是帮你挡掉大部分常见注入,不是万能盾牌。

你贴的这个写法是安全的:User.findOne({ where: { id: req.query.id } }),Sequelize 会把 req.query.id 当成参数绑定,不会直接拼进 SQL,哪怕你传 '1 OR 1=1 --',最后生成的 SQL 类似 WHERE id = '1 OR 1=1 --',数据库会把它当普通字符串匹配,不会执行逻辑,所以没问题。

但重点来了:sequelize.literal()Sequelize.literal() 是危险区。比如:

sequelize.query(SELECT * FROM users WHERE id = ${req.query.id}, { type: QueryTypes.SELECT })


或者

where: {
id: sequelize.literal('${req.query.id}')
}


这种就是你自己拼字符串,ORM 不管你传了啥,直接塞进 SQL,注入风险自己扛。

再比如:

User.findOne({
where: {
name: sequelize.literal(LIKE '%${req.query.keyword}%')
}
})


如果 req.query.keyword%' OR 1=1 --,那就凉了。

总结下:
普通 whereorderinclude 这些字段值,ORM 都会转义,放心用;
一旦你用 literalraw、手写 SQL 字符串拼接,就等于脱了裤子自己上,必须自己做严格校验或转义。

建议:
- 能不用 literal 就别用
- 真要用,至少先 escape 一下,比如:sequelize.escape(req.query.id)
- 关键参数类型校验别偷懒,比如 id 明确是数字就 Number(req.query.id),非数字直接 reject

复制过去试试:

// 安全
User.findOne({ where: { id: "'1 OR 1=1 --'" } })

// 不安全
User.findOne({ where: { id: sequelize.literal("'1 OR 1=1 --'") } })


前者生成 WHERE id = '''1 OR 1=1 --''',后者直接变成 WHERE id = '1 OR 1=1 --',区别自己悟。
点赞 8
2026-02-25 10:01