1.sql注入的原理
在页面参数输入时,输入有语法含义的字符串,这样可以改变你原有的SQL。
例如:
- <?php
- $username = "aaa";
- $pwd = "pwd";
- $sql = "SELECT * FROM table WHERE username = '{$username}' AND pwd = '{$pwd}'";
- echo $sql; //输出 SELECT * FROM table WHERE username = 'aaa' AND pwd = 'pwd'
- ?>
恶意用户 在不知道密码的情况下,通过or关键字来sql注入。
- <?php
- $username = "aaa";
- $pwd = "fdsafda' or '1'='1"; //前面的密码是瞎填的..后来用or关键字..意思就是无所谓密码什么都执行
- $sql = "SELECT * FROM table WHERE username = '{$username}' AND pwd = '{$pwd}'";
- echo $sql; //输出 SELECT * FROM table WHERE username = 'aaa' AND pwd = 'fdsafda' or '1'='1'
- ?>
2.防止sql的原理
将sql语句的执行分成两部分
第一步:先将不带参数的sql进行发给数据库进行预编译。
第二步:将参数和预编译好的sql发给数据库执行。
因为:sql注入只会影响到,sql预编译阶段,执行时就不管参数中的语法关键字了。
注意:MyBatis是如何做到SQL预编译的呢?其实在框架底层,是JDBC中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。
例如:
<select id="getBlogById" resultType="Blog" parameterType=”int”>
SELECT id,title,author,content
FROM blog
WHERE id=#{id}
</select>
这里,parameterType表示了输入的参数类型,resultType表示了输出的参数类型。回应上文,如果我们想防止SQL注入,理所当然地要在输入参数上下功夫。上面代码中黄色高亮即输入参数在SQL中拼接的部分,传入参数后,打印出执行的SQL语句,会看到SQL是这样的:
SELECT id,title,author,content FROM blog WHERE id = ?
不管输入什么参数,打印出的SQL都是这样的。这是因为MyBatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。
但是要注意一个细节
#{}:相当于JDBC中的PreparedStatement
${}:是输出变量的值,没有防止sql注入,需要自己通过技术手段过滤参数来防止sql注入。
例如:同样的sql语句只要把 #{id} 变成 ${id}就不能防止sql注入了。
<select id="getBlogById" resultType="Blog" parameterType=”int”>
SELECT id,title,author,content
FROM blog
WHERE id=${id}
</select>
打印出执行的SQL语句,会看到SQL是这样的:
SELECT id,title,author,content FROM blog WHERE id = 3
参数和语句一起编译的不能,没有采用jdbc的参数绑定方式。