Mybatis Order by动态参数防注入方式
作者:偷代码的猫
这篇文章主要介绍了Mybatis Order by动态参数防注入方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
一、先提及一下Mybatis动态参数
参数符号 | 编译 | 安全 | 值 |
#{} | 预编译 | 安全 | 处理后的值,字符类型都带双引号 |
${} | 未预编译 | 不安全,存在SQL注入问题 | 传进来啥就是啥 |
二、order by 动态参数
order by 后面参数值是表字段或者SQL关键字
所以使用#{} 是无效的,只能使用${}
那么SQL注入问题就来了
三、解决Order by动态参数注入问题
1、使用正则表达式规避
特殊字符 * + - / _ 等等
使用indexOf判断到了直接返回
有可能会存在其它情况,不能完全规避,但是可以逐步排查
2、技巧解决
- 2.1 先从order by 动态参数思考
组合情况只有这两种
- order by 字段名 (asc直接略掉得了)
- order by 字段名 desc
所以我们只要找到对应集合,判断我们动态排序条件是否在其中就可以了
- 2.2 获取排序条件集合
有些勤劳的小伙伴可能就开始写了
userOrderSet = ['id','id desc','age','age desc',.......] scoreOrderSet = ['yuwen','yuwen desc','shuxue','shuxue desc',.......] .............
要是有n多表n多字段可是要急死人
我们使用注解+映射来获取
- 2.3 动态获取集合
/** 首先改造实体类,有@Column注解映射,也有使用@JsonProperty,都行,没有用@Column映射,就加个@JsonProperty,不影响,我偷懒使用@JsonProperty **/ @Data @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class ContentEntity { @JsonProperty("id") private Long id;//主键ID @JsonProperty("code") private String code;//编码 @JsonProperty("content") private String content;//内容 @JsonProperty("is_del") private Integer isDel;//是否删除,0未删除,1已删除 @JsonProperty("creator") private String creator;//创建人 @JsonProperty("creator_id") @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN, timezone = "GMT+8") private Date createAt;//创建时间 @JsonProperty("updater") private String updater;//更新人 @JsonProperty("updater_id") @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN, timezone = "GMT+8") private Date updateAt;//更新时间 }
/**工具类来了**/ public class MybatisDynamicOrderUtils { private static final String desc = " desc"; /** * 获取对象 JsonProperty 值列表 使用Column替换一下 * @param object * @return */ public static Set<String> getParamJsonPropertyValue(Class<?> object){ try { //获取filed数组 Set<String> resultList = new HashSet<>(); Field[] fields = object.getDeclaredFields(); for (Field field:fields){ //获取JsonProperty注解 if(field.getAnnotation(JsonProperty.class)!=null){ JsonProperty annotation = field.getAnnotation(JsonProperty.class); if (annotation != null) { //获取JsonProperty 的值 String jsonPropertyValue = annotation.value(); resultList.add(jsonPropertyValue); } } } return resultList; }catch (Exception e){ e.printStackTrace(); } return null; } /** * 判断动态order是否是合理 * @param order * @param object * @return */ public static Boolean isDynamicOrderValue(String order,Class<?> object){ //先获取JsonProperty 注解中的集合 Set<String> set = getParamJsonPropertyValue(object); //属于直属字段 直接返回 if(set.contains(order)){ return true; } //多了倒序,先去除倒序字段再判断 if(order.lastIndexOf(desc)>0){ String temp = order.substring(0,order.lastIndexOf(desc)); if(set.contains(temp)){ return true; } } return false; } }
//调用操作一下 //检验动态order是否合理,防止SQL注入 if(!MybatisDynamicOrderUtils.isDynamicOrderValue(sort,ContentEntity.class)){ log.error("dynamic order is error:{}",sort); return null; } //mapper.class @Select({"<script>select * from content order by ${sort}</script>"}) List<ContentEntity> getList(@Param("sort") String sort);
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。