在Sequelize中使用findOrCreate时如何防止SQL注入?

夏侯梦森 阅读 52

最近在用Sequelize做用户注册功能时,发现直接拼接查询条件可能会有SQL注入风险。比如这样写:


User.findOrCreate({
  where: {
    username: req.body.username
  },
  defaults: {
    password: req.body.password
  }
})

但查文档后看到应该用参数化查询,可我这样改之后总报错:


User.findOrCreate({
  where: sequelize.literal("username = ?"),
  replacements: [req.body.username],
  defaults: {...}
})

错误提示说找不到正确的参数绑定方式。那正确的findOrCreate参数化写法应该是什么样的?直接用req.body传参到底安不安全?

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
夏侯硕辰
你这问题问得挺实在,不少老手一开始也在这儿栽过跟头。

先说结论:你原代码里直接用 req.body.username 是安全的,Sequelize 的 findOrCreate 默认就会做参数化处理,根本不用你手动写 sequelize.literal 那一套。

问题出在你改写的那一版——where: sequelize.literal("username = ?") 这种写法根本不对。Sequelize 的 findOrCreatewhere 字段支持的对象写法本身就是参数化的,你一用 literal 反而绕过了它的安全机制,还搞乱了参数绑定逻辑。

正确的写法就两行:

where: { username: req.body.username }
defaults: { password: req.body.password }

就这么简单,Sequelize 会自动把 req.body.username 当作参数传进去,生成类似 WHERE username = ? 的语句,底层用的是 mysqlpg 的预处理语句,完全防注入。

你要是真想用 literal(比如要写复杂表达式),得配合 replacements 一起用,但必须注意:replacements 是整个查询语句级别的,不是 findOrCreate 的顶层字段。比如:

User.findOrCreate({
where: sequelize.literal('username = :username OR email = :email'),
replacements: { username: req.body.username, email: req.body.email },
defaults: { password: req.body.password }
})


但这种情况极少用,除非你要写 ORLIKEDATE() 这种 Sequelize 对象写法表达不了的逻辑。

再强调一遍:你原来那版代码是安全的,别自己加戏。只要别手滑拼接字符串(比如 where: { username: 'xxx' + req.body.username }),Sequelize 就能护你周全。

顺带一提:密码记得用 bcrypt 加密存,别直接存明文,这个比 SQL 注入更容易翻车。
点赞 2
2026-02-26 11:07
轩辕文亭
直接用req.body传参是安全的,Sequelize的findOrCreate默认就是参数化查询,你第一种写法根本没问题。where里用literal加replacements是给raw query用的,findOrCreate不认这个。我之前这样搞也踩过坑,后来发现原生的where: { username: req.body.username }自动防注入,别乱改就行。
点赞 9
2026-02-11 11:06