mybatis中的#占位符和$拼接符的区别
为更好地解释mybatis中的#占位符和$拼接符的区别,这里对sql注入做一个简单说明。
一、sql注入
1、什么是sql注入
SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至篡改数据库。
2、sql注入示例
首先定义一个sql字符串,来进行登录操作。
String sql = "select * from user where username=' "+userName+" ' and password=' "+password+" '";
然后输入的用户名为'' or 1 = 1 --
,密码为任意,那么这个sql就会变成下面这样
select * from user where username = '' or 1 = 1 -- and password= ''
因为or 1 = 1
所以前面的username条件会恒成立,在看后边由于--
的存在让and password= ''
被注释掉了,这样语句永远都能正确执行,用户能骗过系统直接登录。
二、#占位符和$拼接符的区别
- # 将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:
where username = #{username}
,如果传入的值是123,那么解析成sql为where username = "123"
, 如果传入的值是zhangsan,则解析成的sql为where username = "zhangsan"
。 - $ 将传入的数据直接显示生成在sql中。如:
where username = ${username}
,如果传入的值是123,那么解析成sql为where username = 123
;如果传入的值是;drop table user;
,则解析成的sql为:select * from user where username = ;drop table user;
- # 方式能够很大程度防止sql注入,$ 方式无法防止Sql注入;$ 方式一般用于传入数据库对象,例如传入表名。
三、mybatis如何防止sql注入
例如:select * from user where username=? and password=?
,不管输入什么参数,打印出的SQL都是这样的。这是因为mybatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符?
就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。
四、总结
在mybatis中,${xxx}
这样格式的参数会直接参与SQL编译,从而不能避免sql注入攻击。但涉及到动态表名和列名时,只能使用${xxx}
这样的参数格式。所以,这样的参数需要我们在代码中手动进行处理来防止sql注入。一般来说,能用#
的就别用$
,若不得不使用${xxx}
这样的参数,要谨慎地做好过滤工作,来防止sql注入攻击。