Sequelize 默认通过参数绑定防范 SQL 注入,所有模型方法(如 findAll、create)均自动参数化;仅 sequelize.query 需手动防护,动态列名、排序字段等须白名单校验。

Sequelize 默认不启用“自动转义”——它压根不用转义,而是全程走参数绑定(prepared statement)路径。所谓“规避 SQL 注入”,本质是靠底层驱动(如 mysql2 或 pg)把值作为独立参数传给数据库执行器,而非拼进 SQL 字符串。你不需要手动开启什么开关,只要用对 API,就天然安全。
哪些 Sequelize 方法默认走参数绑定?
所有模型级方法都自动参数化,包括:
-
findAll()、findOne()、findByPk() -
create()、update()、destroy() -
count()、sum()等聚合方法
只要你传的是 plain object(比如 where: { email: req.query.email }),内部就会把 req.query.email 当作绑定参数,不管它含不含单引号、分号或 --。即使用户输入 "admin' OR 1=1 -- ",最终生成的语句也是类似:
SELECT * FROM users WHERE email = ?
而 ? 对应的值由驱动单独送入,数据库根本不会解析它为 SQL 片段。
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
sequelize.query() 是唯一需要你主动防御的地方
这个方法不走模型逻辑,直接对接 SQL 字符串,所以是否安全完全取决于你怎么写。
- ✅ 安全:用
replacements或bind传参sequelize.query("SELECT * FROM users WHERE status = :status", { replacements: { status: req.body.status } }) - ❌ 危险:模板字符串拼接变量
`SELECT * FROM users WHERE status = '${req.body.status}'`—— 别名、空格、注释都救不了 - ⚠️ 注意:
:status(命名绑定)和?(位置绑定)不能混用;replacements只认命名,bind只认数组顺序
attributes 别名、动态列名、fn/literal 是高危组合点
别名本身不引入风险,但很多人误把它当“安全掩护”去包动态内容:
- ❌ 错误:把用户输入当列名用 ——
attributes: [[req.query.sortBy, 'alias']]
列名无法参数化,必须白名单校验(例如['id', 'name', 'email'].includes(req.query.sortBy)) - ❌ 错误:用
literal()或fn()包用户输入 ——where: { [Op.or]: [fn('LOWER', literal(req.query.q))]
这等于主动绕过参数绑定,把原始字符串塞进 SQL - ✅ 正确:所有值都保持在 where / values 层级,不进
literal、不进 SQL 字符串模板、不进表名/列名位置
真正要检查的不是“有没有转义”,而是“值是否脱离 SQL 字符串上下文”
复杂查询里最容易漏掉的,是那些看起来像“配置项”实则参与 SQL 构建的位置:比如 order: [[req.query.sort, 'ASC']] 中的 req.query.sort,或者 include: { model: User, as: req.query.role } 中的 as。这些都不是参数,不能靠绑定保护,必须做白名单或正则校验。别指望 attributes 或 replacements 能覆盖它们。

















