mybatis中#和$比较、sql注入

《目录》


《内容》

1.mybatis中#{}和${}

1.1 #{}和${}区别

案例:

delete from tab_user where uid = #{uid},jdbcType=INTEGER

sql解析分析:

  1. 上述案例中使用的是#{},sql在解析的时候会加上 " " ,当成字符串来解析 : uid= " uid "
  2. 如果用${},传入数据直接显示在生成的sql中,如上述案例,用uid = ${uid,jdbcType=INTEGER},那么sql在解析的时候值为uid = uid,执行时会报错;

具体区别:

  #{}:

  1. 使用预编译的方式将参数设置到sql语句当中(相当于占位符 ?)
  2. 底层使用的是原生jdbc中的prepareStatrment
  3. 能够在一定程度上防止sql注入的风险(无法避免%的问题

  ${}:

  1. 不适用预编译模式
  2. 去除相应的值直接拼装到sql语句当中
  3. 会有sql注入的安全问题

1.2 #{}和${}应用场景

  1. 大多数情况(如CRUD语句)使用 #{};
  2. 在一些原生jdbc不支持占位符的地方,我们就不能使用#{var}的形式去进行取值,这样会导致执行sql的时候报错,比如传入数据库对象(表名,列名),都需要我们使用${var}的形式直接取值进行字符串的拼接
select XXX from ${year}_${month}_XXX where id = XXX order by ${columnName}

2.sql注入

2.1 sql注入的原因
用于攻击数据驱动的应用,恶意的SQL语句被插入到执行的实体字段中(例如,为了转储数据库内容给攻击者),大家都不陌生,是一种常见的攻击方式。攻击者在界面的表单信息或URL上输入一些奇怪的SQL片段(例如“or ‘1’=’1’”这样的语句),有可能入侵参数检验不足的应用程序。

2.2 #{}防止sql注入的底层原理
假设mapper文件为:

<select id="getNameByUserId" resultType="String">
		SELECT name FROM user where id = #{userId}
</select>

对应的java文件为:

public interface UserMapper{
	String getNameByUserId(@Param("userId") String userId);
}

可以看到输入的参数是String类型的userId,当我们传入userId="34;drop table user;"后,打印的语句是这样的(不管输入何种userID,他的sql语句都是这样的):

select name from user where id = ?

底层原理:这就得益于mybatis在底层实现时使用PreparedStatement类进行预编译语句。预编译sql语句后,再用传入的userId替换占位符?就去运行了。不存在先替换占位符?再进行编译的过程,因此SQL注入也就没有了生存的余地了。
另外,PreparedStaement类不但能够避免SQL注入,因为已经预编译,当N次执行同一条sql语句时,节约了(N-1)次的编译时间,从而能够提高效率。

2.3 避免sql注入的方法

  1. 采用#{},但是在模糊查询时,用concat(’%’, #{}, ‘%’)
  2. 对传入参数进行预处理检查,比如对于上面的userId参数;或者代码白名单的方式限制传入参数(限制 sortBy 允许的值,如只能为 name, email 字段,异常情况则设置为默认值 name
<select id="getUserListSortBy" resultType="org.example.User">  
SELECT * FROM user  
<choose>    
	<when test="sortBy == 'name' or sortBy == 'email'">      
		order by ${sortBy}    
	</when>    
	<otherwise>    
	  order by name    
	</otherwise>    
 </choose>
 </select>
  1. 存储过程。存储过程(Stored Procedure)是一组完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过调用存储过程并给定参数(如果该存储过程带有参数)就可以执行它,也可以避免SQL注入攻击
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值