sql注入大家都不陌生,是一种常见的攻击方式,攻击者在界面的表单信息或url上输入一些奇怪的sql片段
绕过验证,直接登录
SELECT * From Table WHERE Name='XX' and Password='YY';
如果用户随便输入用户名,密码填' or 1=1--
就会成为
SELECT * From Table WHERE Name='SQL inject' and Password='' or 1=1--'
从代码可以看出,前一半单引号被闭合,后一半单引号被 “--”给注释掉,中间多了一个永远成立的条件“1=1”,这就造成任何字符都能成功登录的结果。而Sql注入的危害却不仅仅是匿名登录。
MyBatis是否存在sql注入
mybatis启用了预编译功能,在sql执行前,会先将上面的sql发送给数据库进行编译,执行时,直接使用编译好的sql,替换占位符“?”就可以了。因为sql注入只能对编译过程起作用,所以这样的方式就很好地避免了sql注入的问题。
mybatis是如何做到sql预编译的呢?其实在框架底层,是jdbc中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的sql语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行一个sql时,能够提高效率,原因是sql已编译好,再次执行时无需再编译。
话说回来,是否我们使用mybatis就一定可以防止sql注入呢?当然不是,请看下面的代码:
<select id=“orderBlog“ resultType=“Blog“ parameterType=”map”>
select id,title from blog order by ${orderParam}
</select>
仔细观察,内联参数的格式由“#{xxx}”变为了${xxx}。如果我们给参数“orderParam”赋值为”id”,将sql打印出来,是这样的:select id,title,author,content from blog order by id
显然,这样是无法阻止sql注入的。在mybatis中,”${xxx}”这样格式的参数会直接参与sql编译,从而不能避免注入攻击。但涉及到动态表名和列名时,只能使用“${xxx}”这样的参数格式,所以,这样的参数需要我们在代码中手工进行处理来防止注入。
存储过程也不是绝对能防止sql注入
BEGIN
DECLARE @SQLStatement NVARCHAR(4000)
BEGIN
SELECT @SQLStatement = 'select * from Stations where '
+ @columnName + ' ' + @type + ' ' + '''' + @searchText + ''''
EXEC(@SQLStatement)
END
END
这样存储过程使用了字符串拼接,仍然可以注入。
所以无论你使用SQL语句还是存储过程都没关系,重要的是您的SQL是使用参数还是连接字符串。使用传参可以阻止SQL注入,连接的字符串允许SQL注入。