下面是MyBatis一个Dao配置mysql
<select id="findRank" parameterType ="String" resultType="String">
SELECT u.name FROM UserInfo u
where 1=1
and u.UserID=#{userID} ;
</select>
打印出执行的SQL语句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已编译好,再次执行时无需再编译。数据库
话说回来,是否咱们使用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
假如:
userID=1;drop table UserInfo ;那么sql是这样的测试
SELECT u.name FROM UserInfo u where 1=1 and u.UserID=1;drop table UserInfo ;
测试结果
SELECT u.name FROM UserInfo u where 1=1 and u.UserID=1;drop table UserInfo;
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'drop table UserInfo' at line 3 直接报异常,你应该庆幸mybaties作了处理,可是无论怎么说${xxx}是没法阻止SQL注入的。
“${xxx}”
缺点: 直接参与SQL编译,不能避免注入攻击。
优势:及到动态表名和列名时,只能使用“${xxx}”这样的参数格式
注意: 这样的参数须要咱们在代码中手工进行处理来防止注入。ui
“#{xxx}“
至关于JDBC中的PreparedStatement
${}:是输出变量的值
优势:#{}是通过预编译的,是安全的;spa