mybatis 的坑——java.sql.SQLExceptio

2020-12-15  本文已影响0人  惠惠雨辰

在一次修改动态拼接的表名的sql时,使用#{},一直报错,检查sql没有问题,最终发现,在<select>标签中有这么一个属性statementType="STATEMENT";

statementType="STATEMENT" ,这个属性是不开启预编译,#{}是使用预编译的,导致,sql中的占位符?一直没有被传入的参数所替换掉,所有一直没有找到传入的参数。

之前很多动态拼接表名或者字段名的,都是采用这个,然后入参必须全部是${}才不会报错,但是现在可以不用写这个属性了,默认的开启预处理,也能使用${}。

${} 和 #{}是可以并存的

但是有一点要注意的是,使用${}的时候要注意防止sql注入的问题了

如何防止sql注入?

1.使用#{}一劳永逸,但是特殊的地方,像是表名,字段名就要是'${}'

【底层实现原理】MyBatis是如何做到SQL预编译的呢?其实在框架底层,是JDBC中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。

2.使用正则表达式过滤传入的参数

要引入的包:

import java.util.regex.*;

正则表达式:

private String CHECKSQL = “^(.+)\\sand\\s(.+)|(.+)\\sor(.+)\\s$”;

判断是否匹配:

Pattern.matches(CHECKSQL,targerStr);

下面是具体的正则表达式:

检测SQL meta-characters的正则表达式 :

/(\%27)|(\’)|(\-\-)|(\%23)|(#)/ix

修正检测SQL meta-characters的正则表达式 :/((\%3D)|(=))[^\n]*((\%27)|(\’)|(\-\-)|(\%3B)|(:))/i

典型的SQL 注入攻击的正则表达式 :/\w*((\%27)|(\’))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix

检测SQL注入,UNION查询关键字的正则表达式 :/((\%27)|(\’))union/ix(\%27)|(\’)

检测MS SQL Server SQL注入攻击的正则表达式:

/exec(\s|\+)+(s|x)p\w+/ix

等等…..

3.字符串过滤

比较通用的一个方法:

(||之间的参数可以根据自己程序的需要添加)

public static boolean sql_inj(String str){

String inj_str = "'|and|exec|insert|select|delete|update|

count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";

String inj_stra[] = split(inj_str,"|");

for (int i=0 ; i &lt; inj_stra.length ; i++ ){

if (str.indexOf(inj_stra[i])&gt;=0){

return true;

}

}

return false;

}

4. 确认每种数据的类型,比如是数字,数据库则必须使用int类型来存储

5. 规定数据长度,能在一定程度上防止sql注入

6. 严格限制数据库权限,能最大程度减少sql注入的危害

7. 避免直接响应一些sql异常信息,sql发生异常后,自定义异常进行响应

当然这些中最好的方式还是使用预编译。

上一篇 下一篇

猜你喜欢

热点阅读