在执行MYSQL语句时,有时会遇到大量结构相同仅部分变量不同的语句,直接执行这些语句消耗的时间是巨大的,而预处理则是为这种情况准备的语法。
预处理将SQL语句分为两部分来处理,即固定部分和变量部分。固定部分为SQL语句中相同的语句结构(为了保证SQL语句的完整性,变量部分会采用占位符替代);而变量部分为SQL语句中的不同部分(通常为表明、字段名或条件语句)。预处理过程就像使用模板一样——在固定语句的基础上将变量带入,对于每一句SQL语句来说只需要带入变量然后执行即可。
值得注意的是,预处理仅仅是换了一种执行方式,对于所有的SQL语句都可以采用预处理的方式来执行。但SQL语句在预处理过程中是作为字符串被处理的,这就意味着预处理提供了一种关键字的绕过方式。将SQL语句中那些会被检测的关键词通过一些变化(字符串的处理方式往往是多样的),在预处理时采用相关的方法处理将关键词变回,SQL语句执行的结果在这个过程中并不会收到影响;但是对于关键字检测的WAF来说,WAF检测的是一个中间状态的SQL语句——预处理后才能变回原本的SQL语句,此时WAF便失去了原有的作用。
如前面所述,SQL用预处理的话可以分为固定部分和变量部分。
固定部分:
prepare 预处理后SQL语句的代称 from "SQL语句" ;
这样即获得了一个预处理后的SQL语句后的固定部分,并且将其命名为"sql_1"。
当然如上是没有包含变量部分所以没有占位符,下面则是包含变量部分的另外一SQL语句。
在这句中用"?"作为填充符号替代了条件name=的具体数值。
变量部分
set @变量名=数值;
@在此处的作用类似于PHP中的$符号,这样便设置了一个名为NAME值为'hello'(变量是不区分大小写的,即此处NAME和name均对应值'hello')。
将变量带入并执行
execute 预处理后SQL语句的代称 using 对应SQL语句中涉及到的变量;
以此前获得的sql_2为例,将设置好的变量name值带入并执行该SQL语句。
如果存在多个变量时需要用逗号隔开。
删除固定部分
drop prepare 预处理后SQL语句的代称;
删除一个生成的固定部分。
因为在预处理语法中设置了变量,所以可以对变量赋值处理后的SQL语句。这里的SQL语句均采用"select * from test;",如果有变更则会另行说明,主要思想还是依靠MYSQL中丰富的字符串处理函数。
利用char函数。
char函数可以把10进制转换成对应ASCII字符,而且对于MYSQL来说可以同时传入多个10进制数值,最终结果会拼凑为一个字符串。
利用16进制。
0x+16进制的格式MYSQL会转化为16进制对应的字符串。
利用reverse函数。
把字符串反转基本山WAF也查不出来。
如果文中有不当之处,欢迎各位师傅的斧正。因为是参考过了其他师傅的文章,所以在叙述上会与其他师傅有相似的表达。