介绍
在nodejs中使用sequlize库来查询mysql数据库, 提供了常用的方法有两种:
- 直接查询sql语句:
sequelize.query()
; - 通过接口,如
Project.findAll()
;
- 直接查询sql语句:
sequelize的第2种查询方法在实现上做了防注入处理, 但该方法使用并不是很灵活, 对于经常使用原生sql语句的人来说, 总有一种不适应, 感觉手脚被束缚; 而对于使用方法1, 则必须注意防sql注入;
这里我测试前面提到的两种查询方式如何做到初步的防sql注入功能;
sql注入
产生原因
下面的查询语句, 加入了用户输入的时间项: begin
, end
, 正常情况是:
begin = 20161101;
SELECT .. FROM tbl WHERE pdate>=20161101 AND ...;
而如果有人故意输入如下的参数, 则就会出现sql注入:
begin = '20161101 AND 1=1; -- hack';
SELECT .. FROM tbl WHERE pdate>=20161101 AND 1=1; -- hack ...;
解决办法
解决上面的办法, 通常有两种:
1. 对输入的参数进行转义, 因为sql注入通常需要'
符号来闭合前面的'
, 这样如果位面在输入的参数中的'
全部转义为\'
, 则查询时就不会出现中断(执行两条sql语句), 参看下面的例子;
2. 设置mysql只能一次执行一条sql语句;
测试
sequelize.query()
与Project.findAll()
对比
先看代码
var tblName = 'tbl_test', begin = '20160923 AND 1=1;-- hack', end = 20160928;
var sqlQuery = `SELECT * FROM ${tblName} WHERE pdate>=${begin} AND pdate<=${end} GROUP BY pdate`;
Promise.resolve([
// 第一条查询
sequelize.query(sqlQuery),
// 第一二条查询
Project.findAll({
attributes: { exclude:['id'] },
where: {
pdate: {
$and:{
// 参数中加上了'来闭合前面的', 后面的1=1为注入语句
$gte: "20160923' AND 1=1;-- hack",
$lte: end
}
}
}
})
]).spread(function(sql1, sql2){
})
- 上面第一个为
sequelize.query()
执行, 最终执行的查询语句为:
select * from tbl_test where padte>=20160923 and 1=1;-- hack and pdate<=....;
结果出现注入,
pdate<=..
这一块的条件没有被执行;
- 上面第二个查询为
Project.findAll()
执行, 最终执行的语句为:
select * from tbl_test where pdate>'20160923\' AND 1=1;-- hack' AND pdate<='...'.....;
显然,这里参数里的
20160923'
引号没有起作用, 被转换为了`20160923\”,所以有效避免了注入, 制查询了符合要求的数据或空数据;
sequelize.query()
+ 参数绑定
下面通过sequelize.query()
接口提供的参数绑定和查询方法指定来防止sql注入的发生.
- 下面的查询语句解析为:
select * from tbl_test where padte>='20160923 and 1=1;-- hack' and pdate<=....;
字符串被直接替换,没有被注入;- 注意,这里的表名table不能通过bind的参数传进去, 因为这样在语句里会表达为字符串: …. from ‘tbl_test’ where …, 这样是错误的语句,所以上面用字符串模板传入,也可以硬编码进去;
var tblName = 'tbl_test', begin = '20160923 AND 1=1;-- hack', end = 20160928;
var sqlQuery = `SELECT * FROM ${tblName} WHERE pdate>=$begin AND pdate<=$end GROUP BY pdate`;
Promise.resolve([
sequelize.query(sqlQuery,
type: ymModel.sequelize.QueryTypes.SELECT, // 指定sql为SELECT
bind: {
begin: begin,
end: end
}
),
]).spread(function(sql1){
})