前言
1、回顾什么是sql注入
2、mybatis如何解决sql注入
一、sql注入及mybatis防止sql注入
1.1Sql 注入产生原因及威胁
当我们访问动态网页时, Web 服务器会向数据访问层发起 Sql 查询请求,如果权限验证通过就会执行 Sql 语句。这种网站内部直接发送的Sql请求一般不会有危险,但实际情况是很多时候需要结合用
户的输入数据动态构造 Sql 语句,如果用户输入的数据被构造成恶意 Sql 代码,Web 应用又未对动态构造的 Sql 语句使用的参数进行审查,则会带来意想不到的危险。
Sql 注入带来的威胁主要有如下几点:
- 猜解后台数据库,这是利用最多的方式,盗取网站的敏感信息。
- 绕过认证,列如绕过验证登录网站后台。
- 注入可以借助数据库的存储过程进行提权等操作。
1.2Mybatis防止sql注入
下面是MyBatis一个Dao配置
<select id="findRank" parameterType ="String" resultType="String"> SELECT u.name FROM UserInfo u where 1=1 and u.UserID=#{userID} ; </select>
打印出执行的SQL语句
SELECT u.name FROM UserInfo u where 1=1 and u.UserID=?
这是因为MyBatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这
样的方式就很好地避免了SQL注入的问题。
- 底层实现原理
MyBatis是如何做到SQL预编译的呢?其实在框架底层,是JDBC中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这
种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。PreparedStatement只能用来为参数(如参数值)设置动态参数,即用?占位,不可用于表名、字段名等。
话说回来,是否我们使用MyBatis就一定可以防止SQL注入呢?当然不是,请看下面的代码:
<select id="findRank" parameterType ="String" resultType="String"> SELECT u.name FROM UserInfo u where 1=1 and u.UserID=${userID} ; </select>
假设userID=1,将SQL打印出来是这样的:
SELECT u.name FROM UserInfo u where 1=1 and u.UserID=1
显然${}这种方式直接参与sql编译,将传入的参数直接显示生成在sql中,不能避免注入攻击。
1.3mybatis${ } 和 #{ }区别
- #方式能够很大程度防止sql注入。
- $方式无法防止Sql注入。
- $方式一般用于传入数据库对象,例如传入表名。
${xxx}
- 缺点: 直接参与SQL编译,不能避免注入攻击。
- 优点:及到动态表名和列名时,只能使用“${xxx}”这样的参数格式
- 注意:这样的参数需要我们在代码中手工进行处理来防止注入。
- ${}将传入的参数直接显示生成在sql中,不会添加引号
#{xxx}
- 相当于JDBC中的PreparedStatement
- #{}将传入的参数当成一个字符串,会给传入的参数加一个双引号
- 优点:#{}是经过预编译的,是安全的;
参看链接:https://blog.csdn.net/cristianoxm/article/details/123726070