麻烦死了,用正则是不是简单些
public class SQLParamChecker {
// 关键字
private static List<String> SPECIAL_WORDS;
private static BloomFilter<String> FILTER;
static {
FILTER = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), 100000, 0.01);
SPECIAL_WORDS = ZYFileUtils.readClassPathFile2List("sql_special_key.txt");
// 单词的长短倒序,先判断长的,再判断误的,避免长的包含短的误关 如into in这种,先判断into,再判断in
SPECIAL_WORDS.sort(Comparator.comparing(String::length).reversed());
}
public static void main(String[] args) {
String sql1 = "select Icollect'and(select*from(select+sleep(2))a/**/union/**/select+1)=' select";
String sql2 = "select ";
checkExistsIllegalSQL(sql1);
checkExistsIllegalSQL(sql2);
checkExistsIllegalSQL(sql2);
}
public static void checkExistsIllegalSQL(String context) {
if (ZYStrUtils.isNull(context)) {
return;
}
if (FILTER.mightContain(context)) {
return;
}
// 统一转为小写
String text = context.toLowerCase();
if (text.contains("'")) {
throw new IllegalSqlException();
}
// 检查是否存在关键字
if (hasSpecialWord(text)) {
throw new IllegalSqlException();
}
if (context.length() < 30) {
// 小于30(经验值)的短参数直接跳过去,用布隆过滤器不知道有没有问题,会有一定的内存溢出风险,比起大量循环判断来说。还是值得一试
FILTER.put(context);
}
}
private static boolean hasSpecialWord(String text) {
for (String specialWord : SPECIAL_WORDS) {
// 等于关键字无所谓
if (text.length() == specialWord.length()) {
return false;
}
// 找到关键字索引
List<Integer> indexs = findPlaceLocal(text, specialWord);
if (indexs.size() == 0) {
continue;
}
for (Integer index : indexs) {
// 前置检查
boolean isPreSpecialSymbol;
if (index == 0) {
// 关键字开头
isPreSpecialSymbol = true;
} else {
String preLatter = text.substring(index - 1, index);
// 前置字母被关键字包裹
isPreSpecialSymbol = isSpecialSymbol(preLatter);
}
// 后置检查
int beginIndex = index + specialWord.length();
int endIndex = beginIndex + 1;
boolean isAfterSpecialSymbol;
if (endIndex >= text.length()) {
// 关键字结尾
isAfterSpecialSymbol = true;
} else {
String postLetter = text.substring(beginIndex, endIndex);
// 后置字母被关键字包裹
isAfterSpecialSymbol = isSpecialSymbol(postLetter);
}
// 检测到关键字,并且关键字的前后是非字母相连,判断为sql关键字 (select *这种 xxxselectxx 这种不算
if (isPreSpecialSymbol && isAfterSpecialSymbol) {
return true;
}
}
}
return false;
}
private static List<Integer> findPlaceLocal(String text, String word) {
int index = 0;
List<Integer> placeIndexs = new ArrayList<>();
while (index != -1) {
index = ZYStrUtils.indexOf(text, word, index, false);
if (index != -1) {
placeIndexs.add(index);
index = index + word.length();
}
}
return placeIndexs;
}
private static boolean isSpecialSymbol(String letter) {
char aChar = letter.toCharArray()[0];
char line='_';
// 数字、字母、下划线
boolean isLatter = aChar <= 9 || (aChar >= 97 && aChar <= 122) || aChar == line;;
return !isLatter;
}
}