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

迷人的志红 阅读 8

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

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

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

我来解答 赞 2 收藏
二维码
手机扫码查看
1 条解答
シ雯婷
シ雯婷 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 --',区别自己悟。
点赞 2
2026-02-25 10:01