一种低版本mybatisPlus SQL注入攻击解决办法

对https://blog.csdn.net/qq_37148232/article/details/135238622?spm=1001.2014.3001.5501作了下升级。使用切面对入参作全面检查。以解决低版本mybatisPlus所带来的sql注入问题。

public class IllegalSQLCheckExecutor  {

    private static JSONConfig jsonConfig;

    private static Set<String> IGNORE_FIELDS = new HashSet<>();

    static {
        jsonConfig = JSONConfig.create();
        // 使用的是hutool json工具
        jsonConfig.setIgnoreNullValue(true);
        jsonConfig.setIgnoreError(true);
        
        IGNORE_FIELDS.add("pageNo");
        IGNORE_FIELDS.add("pageSize");
        // 跳过一些常用字段...
    }


    // springAOP前置通知,拦截controller
    public void before(Object[] args, Signature signature) {
        for (Object arg : args) {
            if (null == arg) {
                continue;
            }
            
            Class<?> argClass = arg.getClass();
            String className = argClass.getName();
            // 只检测本公司包名下的参数类型
            if (!className.contains("zysoft")) {
                continue;
            }
            
            try {
                checkIllegalSQL(JSONUtil.parseObj(arg, jsonConfig));
            } catch (IllegalSqlException ie) {
            	// sql检测异常
                throw new LocalException("illegal parameters has been detected!");
            } catch (Exception e) {
            	// 其他异常跳过,不影响正常逻辑
                log.warn(e.getMessage());
            }
        }
    }

    private void checkIllegalSQL(JSONObject jsonObject) {
        Set<String> keys = jsonObject.keySet();
        if (keys.isEmpty()) {
            return;
        }

        for (String key : keys) {
        	// 跳过忽略的通用Key
            if (IGNORE_FIELDS.contains(key)) {
                continue;
            }
            Object valueObj = jsonObject.getObj(key);
            if (null == valueObj) {
                continue;
            }
			// 只检测字符类型
            if (valueObj instanceof String) {
                String str = String.valueOf(valueObj);
                SQLParamChecker.checkExistsIllegalSQL(str);
                continue;
            }
			// 递归检测对象
            if (valueObj instanceof JSONObject) {
                JSONObject paramObject = (JSONObject) valueObj;
                checkIllegalSQL(paramObject);
                continue;
            }
			// 递归检测数组
            if (valueObj instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) valueObj;
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONObject arrayObject = jsonArray.getJSONObject(i);
                    checkIllegalSQL(arrayObject);
                }
            }
        }
    }
}

检测工具类改进:

public class SQLParamChecker {
    // 关键字
    private static List<String> SPECIAL_WORDS;
    // 特殊符号
    private static List<String> SPECIAL_SYMBOL;

    static {

        SPECIAL_WORDS = ZYFileUtils.readClassPathFile2List("sql_special_key.txt");

        SPECIAL_SYMBOL = ZYFileUtils.readClassPathFile2List("sql_special_symbol.txt");
    }

    public static void checkExistsIllegalSQL(String context) {
        if (ZYStrUtils.isNull(context)) {
            return;
        }

        // 统一转为小写
        String text = context.toLowerCase();

        // 检查是否存在关键字
        boolean hasSpecialWord = ZYListUtils.anyMatch(SPECIAL_WORDS, text::contains);
        boolean hasSpecialSymbol = ZYListUtils.anyMatch(SPECIAL_SYMBOL, text::contains);
        // 同时带有关键字和SQL符号的注入才是完整的注入,否则不会生效。会被''符号视为字符串,
        // 本判断依本公司实际情况和等保测评公司常用检测手段得来的,该判断并非绝对,应对等保公司测评应该问题不大。也能防止一些参数误判。
        // 如后续有漏洞再更新本文章,
        if (hasSpecialWord && hasSpecialSymbol) {
            throw new IllegalSqlException();
        }
    }
}

sql_special_key.txt

add
modify
values
set
rollback
commit
database
in
on
alter
create
select
update
and
or
delete
insert
truncate
substr
ascii
exec
count
count
master
into
drop
execute
table
char
declare
sitename
xp_cmdshell
like
from
grant
use
group_concat
column_name
information_schema.columns
table_schema
union
where
order
by

sql_special_symbol.txt

*
;
--
+
,
%
)
(
'
=
   public static List<String> readClassPathFile2List(String fileName) {
        String context = readClassPathFile2String(fileName);
        List<String> list = new ArrayList<>();
        if (ZYStrUtils.isNull(context)) {
            return list;
        }
        StringTokenizer stringTokenizer = new StringTokenizer(context);
        while (stringTokenizer.hasMoreElements()) {
            String nextToken = stringTokenizer.nextToken();
            if (ZYStrUtils.isNotNull(nextToken)) {
                list.add(nextToken);
            }
        }
        return list;
    }

    public static String readClassPathFile2String(String fileName) {
        ClassPathResource resource = new ClassPathResource(fileName);
        try (InputStream inputStream = resource.getStream()) {
            return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
        } catch (IOException e) {
            return null;
        }
    }
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值