MyBatis之bind标签详解,bind预防SQL注入案例及详解

1、bind标签

bind 标签可以使用 OGNL 表达式创建一个变量井将其绑定到上下文中

语法:

name:为上下文的变量,如SQL中存在#{userName}变量,这里name就填写userNamevalue:绑定变量的最终值,如name="userName",那么value就是#{userName}的最终实际值,可以对传递的参数进行处理,如:value = " '%' + userName + '%' ",给传入的userName拼接前后%符号。

2、作用

1>兼容不同数据库之间的SQL语法差异,对数据库迁移友好

由于不同数据库的部分SQL写法存在差异,使用bind可以适配不同数据库之间的差异

如:模糊查询时,使用concat字符串拼接函数,在MySQL中支持多个参数,而Oracle中只能写两个参数,如下:

MySQL写法:

select id,serial from payment

where

serial like concat("%",#{serial},"%")

Oracle写法:

select id,serial from payment

where

serial like concat("%",concat(#{serial},"%"))

因此,在Oracle迁移至MySQL时,会导致mybatis报错,我们可以使用bind标签直接兼容,如下:

select id,name from payment

where

name like #{name} --name实际是bind标签中的value

2>防止SQL注入

以模糊查询为例,当我们不使用concat函数,直接使用SQL字符串拼接时,如下:

select id,serial from payment

where

serial like "%${serial}%"

--注意:Oracle写法为:"%"||${serial}||"%"

注意:这里只能为:"%${serial}%",不能是"%#{serial}%"

"%${serial}%":${serial}会看成字符串占位符,当运行SQL时直接替换该部分"%#{serial}%":#{serial}在字符串拼接时,不会生效,直接就是一个"%#{serial}%"字符串

我们测试上述SQL模糊查询语句,SQL注入案例:

<1>MySQL存在payment表数据

<2>mybatis映射XML

<3>controller接口

service、dao层代码直接省略了,没有任何处理,直接会调用xml中的SQL

@RequestMapping("/payment/getBySerial")

public R> getBySerial(PaymentDTO dto){

return R.ok(paymentService.getBySerial(dto));

}

<4>测试

测试正常请求:http://127.0.0.1:6061/payment/getBySerial?serial=O

此时执行的SQL语句为:

select id,serial from payment where

serial like "%O%"

测试SQL注入请求:http://127.0.0.1:6061/payment/getBySerial?serial=O" or 1=1 or "serial=O

此时执行的SQL语句为:

select id,serial from payment where

serial like "%O" or 1=1 or "serial=O%"

!!!or 1 = 1 :过滤条件直接失效,能获取到表中的所有数据!,如下:

<5>bind防止SQL注入修改

因此,上述写法我们不能使用#{}去防止SQL注入,在不使用SQL函数和java代码不拼接%的情况下,我们想预防SQL注入,可以使用bind标签+#{}去替换${}拼接方式,案例如下:

更改xml中的SQL,其他代码不动:

select id,serial from payment where

serial like #{serial}

继续测试:

测试正常请求:http://127.0.0.1:6061/payment/getBySerial?serial=O

此时执行的SQL语句为:

请求结果:

测试SQL注入请求:http://127.0.0.1:6061/payment/getBySerial?serial=O" or 1=1 or "serial=O

此时执行的SQL语句为:

结果如下: