如何在 sequelize raw query 中如何避免 SQL injection

tl;dr: 结论:在 Sequelize.query() 函数中使用 replacements 对SQL变量赋值。

由于 sequelize 能力有限,一些复杂的查询需求还难通过 sequelize 的 op 的组合来实现,比如 postgresql 中的select distinct on (field)这样的语法

SELECT DISTINCT ON ("fault_id") event.* from event
AND "tenant_id"= '93283d50c03f11e7a2c0a7b189d903d8' \
AND (deleted_at > CURRENT_TIMESTAMP or deleted_at is null) \
ORDER BY fault_id, occur_time desc

因此,我们会考虑使用 Sequelize.query() 原生的查询方式,并且通常会使用 js 的 raw string 来拼接 sql,这里就容易存在 SQL 注入的风险。例如:

const name='boom';
yield Sequelize.query(`SELECT *  from event from "name"= '${name}'`, {});

上面是正常的情况,假如我们信任某个参数的值,这样的写法问题不大。但是假如有用户恶意输入一些特殊字符,就能攻击系统了。如下:

const name="boom';delete from user;";
yield Sequelize.query(`SELECT *  from event from "name"= '${name}'`, {});

不过 sequelize 已经考虑到这些风险,我们可以通过 replacements 这个参数(相当于预处理)来解决这个问题。

const name="boom';delete from user;";
yield Sequelize.query(`SELECT * from event from "name"= :name`, {
	replacements: {name: name}
});

replacements 中的参数值中的特殊字符,比如 ‘ (single quote) 会被转义。

结论:当我们在 sequelize 中使用 raw query 时,要使用 replacements 参数来给SQL中的变量赋值,避免SQL注入风险。

-> reference: