基于Validator排序字段防SQL注入

让人想犯罪 __ 提交于 2020-08-14 20:18:08

一、定义排序基类

public interface BaseSortModel {

    String getSort();

    @ApiModelProperty(hidden = true)
    default String getSortField() {
        if (StringUtils.isNotBlank(getSort()) && getSort().contains("-")) {
            return getSort().split("-")[0];
        }
        return null;
    }

    @ApiModelProperty(hidden = true)
    default String getSortType() {
        if (StringUtils.isNotBlank(getSort()) && getSort().contains("-")) {
            return getSort().split("-")[1];
        }
        return null;
    }

}

二、定义校验注解

@Target({ FIELD,   PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {Sort.SortValidator.class})
public @interface Sort {
    String message() default "不支持的排序字段";

    Class<?>[] FieldOfClass() default {};

    String[] fields() default {};

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

三、定义校验器


@Slf4j
    class SortValidator implements ConstraintValidator<Sort, String> {

        private static Map<String, Set<String>> supportBeanFields = Maps.newConcurrentMap();
        private static List<String> supportSortTypes = Lists.newArrayList("asc", "ASC", "desc", "DESC");

        private Sort sortAnn;

        @Override
        public void initialize(Sort ann) {
            this.sortAnn = ann;

            if (ArrayUtils.isNotEmpty(sortAnn.FieldOfClass())) {
                for (Class<?> clz : sortAnn.FieldOfClass()) {
                    Set<String> clzFields = supportBeanFields.get(clz.getName());
                    if (Objects.nonNull(clzFields)) {
                        continue;
                    }
                    Field[] fields = clz.getDeclaredFields();
                    if (ArrayUtils.isEmpty(fields)) {
                        supportBeanFields.putIfAbsent(clz.getName(), Sets.newHashSet());
                        continue;
                    }
                    clzFields = Sets.newHashSetWithExpectedSize(fields.length * 2);
                    for (Field field : fields) {
                        field.setAccessible(true);
                        clzFields.add(field.getName());
                        clzFields.add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName()));
                    }
                    supportBeanFields.putIfAbsent(clz.getName(), clzFields);

                }

            }
        }

        /**
         * 校验排序字段
         *
         * @param value     值
         * @param context   校验器上下文
         * @return          是否校验成功
         */
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            if (StringUtils.isEmpty(value)) {
                return true;
            }

            if (!SQLFilter.checkSqlInject(value)) {
                return false;
            }

            String[] split = value.split("-");
            if (split.length != 2) {
                log.error("排序字段格式格式有误,比如[字段名-asc]");
                return false;
            }

            String sortField = split[0];
            String sortType = split[1];

            if (ArrayUtils.isEmpty(sortAnn.fields()) && ArrayUtils.isEmpty(sortAnn.FieldOfClass())) {
                log.error("排序字段必须限定枚举值,请对@sort的fields或者fieldOfClass赋值)");
                return false;
            }

            boolean isSupport = false;
            if (ArrayUtils.isNotEmpty(sortAnn.fields())) {
                if (ArrayUtils.contains(sortAnn.fields(), sortField)) {
                    isSupport = true;
                }
            }

            if (ArrayUtils.isNotEmpty(sortAnn.FieldOfClass())) {
                for (Class<?> clz : sortAnn.FieldOfClass()) {
                    Set<String> supportFields = supportBeanFields.get(clz.getName());
                    if (supportFields.contains(sortField)) {
                        isSupport = true;
                        break;
                    }
                }
            }

            if (!supportSortTypes.contains(sortType)) {
                log.error("不支持的排序类型, 仅支持[asc、desc]");
                return false;
            }
            return isSupport;
        }
    }

四、SQL注入校验工具类


@Slf4j
public class SQLFilter {

    public static String[] illegalKeywords = {"'", "\"", ";", "\\", "master", "truncate", "insert", "select", "delete", "update", "declare", "alert", "drop"};
    /**
     * SQL注入校验
     *
     * @param param  待验证的字符串
     */
    public static String sqlInject(String param){
        if(StringUtils.isBlank(param)){
            return param;
        }

        String lowerParam = param.toLowerCase();

        for(String illegalKeyword : illegalKeywords){
            if(lowerParam.contains(illegalKeyword)){
                throw new ParameterException(ReturnCode.PARAM_ERROR,
                        "参数:[" + param + "],含非法关键词[', \", ;, \\, master, truncate, insert, select, delete, update, declare, alert, drop]");
            }
        }
        return param;
    }

    /**
     * SQL注入校验
     *
     * @param param  待验证的字符串
     */
    public static boolean checkSqlInject(String param){
        if(StringUtils.isBlank(param)){
            return true;
        }

        String lowerParam = param.toLowerCase();

        for(String illegalKeyword : illegalKeywords){
            if(lowerParam.contains(illegalKeyword)){
                return false;
            }
        }
        return true;
    }
}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!