Mybatis防止SQL注入攻击

相比于ORM框架,Mybatis只能被称为半自动持久层框架,它其实是将JDBC进行了轻量级的封装,提供SQL映射能力,便于更为方便地管理项目中的SQL代码,同时避免程序员重复手动编写连接数据库底层代码,并提供数据缓存能力。

JDBC在使用时存在SQL注入攻击的风险,同样需要进行SQL编写的Mybatis同样也有这个问题,在使用时需要注意,防止被别有用心的人利用。

那么在Mybatis中如何避免SQL注入攻击呢?

答:在SQL映射文件中尽量使用#指示符标识参数位置,避免使用$。

我们通过简短的程序来看这二者实际有什么不同。

首先我们使用$符号来注入参数

<select id="getCustomerCar" resultType="map">
    select * from tb_customer_car t where t.customer_id = ${customerId}
</select>

测试用的Java代码:

@Test
public void testGetCustomerCar(){
    TestService service = new TestService();
    try {
        Map<String,Object> parameters = new HashMap<>();
        //如果使用SQL拼接将or 1=1拼接进SQL,那么攻击者就能窃取到tb_customer_car表中的所有数据
        parameters.put("customerId", "1 or 1=1");
        service.getCustomerCar(parameters);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

程序输出结果:

==>  Preparing: select * from tb_customer_car t where t.customer_id = 1 or 1=1 
==> Parameters: 
<==    Columns: customer_id, brand, model
<==        Row: 1, 福特, 福克斯
<==        Row: 2, 雪佛兰, 科鲁兹
<==      Total: 2

可以看到使用$指示符时Mybatis在编译时将1 or 1=1直接拼接进了SQL语句中,从而导致攻击者获取到所有的数据。

我们将$替换为#来注入参数:

<select id="getCustomerCar" resultType="map">
    select * from tb_customer_car t where t.customer_id = #{customerId}
</select>

程序输出结果:

==>  Preparing: select * from tb_customer_car t where t.customer_id = ? 
==> Parameters: 1 or 1=1(String)
<==    Columns: customer_id, brand, model
<==        Row: 1, 福特, 福克斯
<==      Total: 1

从输出结果可以看出,#标识的参数被预编译为了占位符?,1 or 1=1是作为参数来替换占位符。

这里查询出了customer_id为1的数据,是因为cutomer_id字段是int型的,在Mysql中将int类型数据和varchar类型数据比较判断时,会将varchar的首字符转化为数字来和int类型数据比较判断。

因此,为了防止SQL注入攻击,在使用Mybatis时我们应尽量使用#而不是$来注入参数

展开阅读全文

没有更多推荐了,返回首页