7、SQL预编译和SQL注入以及mybatis如何防止SQL注入
转载帖子来源:https://blog.csdn.net/weixin_33728708/article/details/90620309
1.先谈 SQL注入
SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过让原SQL改变了语义,达到欺骗服务器执行恶意的SQL命令。其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。
其实,反过来考虑,这也是SQL这类解释性语言本身的缺陷,安全和易用性总是相对的。类似的ShellShock也是一种注入攻击,可以看《ShellShock漏洞原理分析》。
2.再说SQL预编译(PreparedStatement)
前面说了,SQL之所以能被注入,最主要的原因就是它的数据和代码(指令)是混合的。
其实我们想一下,C程序为什么从来没听说过注入这种说法,有的也是溢出。这是因为C是一种编译型语言,你没法在语义上欺骗它,语义解析这步提前做了,都生成二进制了。所以攻击C的方式大多是溢出,通过溢出让数据覆盖指令段。
数据库也提供了这种分离数据和代码(指令)的方式,就是SQL预编译。而SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or ‘1=1’也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令。
理论上,SQL预处理对注入的解决是釜底抽薪的。但貌似有的预处理依然是平凑的方式,仅仅是加了过滤。这还需要数据库支持。
3.总结
mybatis的#{}其实就用到了预编译来防止SQL注入,上面内容也说了,预编译有两个好处,第一个就是先编译成数据库可以识别运行的语言,同时预编译一次,如果SQL需要多次执行,那么也就可以省去了每次都编译的过程,节省了很多时间;
然后还有个好处就是例如mybatis的#{}就是个占位符,比如 select * from user where name=#{name}; 预编译完就是 select * from user where name=?; 类似于这样的语句,然后真正执行的时候,?会被替换成值,而即使是sql注入,注入的语句也只能作为值! 而不是sql语句来执行;
依次来防止SQL注入。