一. 什么是SQL 注入
关于SQL 注入在科普中国的词条上是这样解释的:SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
在mybatis 中最常见的注入风险是书写的时候使用${}
来举一个很简单反例
select name from user_info where id = ${id}
正例
select name from user_info where id = #{id}
Mybatis 中这样书写SQL 语句无疑是有SQL 注入风险的,为什么${} 有注入的风险而#{} 没有注入风险?
在来理清#{} 和 ${}的区别之前我们先回顾 preparedstatement和statement的其中一些区别
1、PreparedStatement是预编译的,可以批量处理数据,statement则相反。
2、传递给PreparedStatement对象的参数可以被强制进行类型转换,statement则相反。
3 、 #{ }是预编译处理,MyBatis在处理#{ }时,它会将sql中的#{ }替换为?,然后调用PreparedStatement的set方法来赋值,传入字符串后,会在值两边加上单引号,如上面的值 “1,ab,c”就会变成“ ‘1,ab,c’ ”
4、 是 字 符 串 替 换 , M y B a t i s 在 处 理 { }是字符串替换, MyBatis在处理 是字符串替换,MyBatis在处理{ }时,它会将sql中的${ }替换为变量的值,传入的数据不会加两边加上单引号。
使用${ }会导致sql注入!
二 、 在mybatis 中常犯的错误有以下三种
1. 模糊查询
反例
select name from user_info where name like ‘%${name}%’
有些程序员不留意就会犯这个错误,因为以下的写法Mybatis 是会报错的,所以选择用了 ${name}
select name from user_info where name like ‘%#{name}%’
// 这样写Mybatis 会报错
解决方案:
正例
select name from user_info where name like concat(‘%’,#{name}, ‘%’)
2. in 之后传的参数
同样的在in 之后使用 #{} Mybatis 也会报错,很多同事会用${} 代替
反例
select name from user_info where id in (${ids})
解决方案:
正例
select name from user_info where id in <foreach collection="ids" item="item" open="("separatosr="," close=")">
3. order by 之后传的参数
同样的在order by 之后使用 #{} Mybatis 也会报错,很多同事会用${} 代替
反例
select name from user_info order by ${id}
解决方案:
正例
select name from user_info order by concat(‘%’,#{id}, ‘%’)