接收到前端参数,对参数的值进行校验,收集了一些常见的绕过方式
public class CheckSqlParamUtils {
/**
* 对前端的传参进行校验,对除了了id外的每个参数进行校验,true为未通过sql注入校验
* @param map
* @return
*/
private static final Logger logger = LoggerFactory.getLogger(CheckSqlParamUtils.class);
public static boolean mapCheck(Map<String,String> map){
if (map.isEmpty()){
return false;
}
for (Map.Entry<String, String> entry : map.entrySet()) {
if(!"id".equals(entry.getKey())){
if (sqlCheck(entry.getValue())){
return true;
}
}
}
return false;
}
public static boolean sqlCheck(String sql) {
sql = sql.toUpperCase();
//注入字符校验
String dangerWord = "exec|insert|select|delete|update|union|and|from|database|drop|create|like|rlike|regexp|count|chr|truncate|declare|or|join|offset" +
"all|alter|kill" ;
String dangerWordUpper = dangerWord.toUpperCase();
String dangerWordArr[] = dangerWordUpper.split("\\|");
for (int i = 0 ; i < dangerWordArr.length; i++ ) {
String key = dangerWordArr[i];
if(sql.contains(" " + key)
|| sql.contains(key + " ")
|| sql.contains(key+"(")){
logger.info("未通过sql关键字校验,未通过值为",sql);
return true;
}
}
//注入函数校验
String dangerFun = "mid(|char(|ascii(|substr(|abs(|rand(|exp(|concat(|CHARSET(|VERSION(|CONNECTION_ID(|COUNT(|" +
"AVG(|sign(|INSERT(|greatest(|least(strcmp(|left(|right(|ascii(|hex(";
if (containDangerKey(sql,dangerFun,"\\|")){
logger.info("未通过sql函数校验,未通过值为",sql);
return true;
}
//针对空格绕过校验
String dangerBlank = "%20|%09|%0a|%0b|%0c|%0d|%a0|%00|/*|*/|/*!*/\\N|";
if (containDangerKey(sql,dangerBlank,"\\|")){
logger.info("未通过sql空格绕过校验,未通过值为",sql);
return true;
}
//针对特殊字符校验
String dangerMark = ".I;I:I#I%I+I-I=I//I@I\"I--I<I>I&&I||I`";
if (containDangerKey(sql,dangerMark,"I")){
logger.info("未通过sql特殊符号校验,未通过值为",sql);
return true;
}
return false;
}
public static boolean containDangerKey(String sql, String dangerStr,String regex){
String dangerStrLow = dangerStr.toLowerCase();
String[] dangerStrs = dangerStrLow.split(regex);
for (int i = 0; i < dangerStrs.length; i++) {
String key = dangerStrs[i];
if(sql.contains(key)) {
return true;
}
}
return false;
}
}