Mybatis动态传入order by问题
吾爱主题
阅读:179
2022-12-30 17:11:00
评论:0
Mybatis动态传入order by
当Mybatis的mapper文件传入的order by 为动态参数说的时候发现排序无法生效:
像下面这样,在choose when中的order by后的参数是用预编译的方式,用的是#号,这样是可以防止sql注入的问题,但是在传入order by参数的时候无法解析:
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | < select id= "feescaleList" resultType= "com.hasagei.modules.mebespoke.entity.HasageiMeBespoke" parameterType= "com.hasagei.modules.mebespoke.entity.HasageiMeBespoke" > SELECT A.ID AS id, TO_CHAR(A.BESPOKE_DATE, 'yyyy-mm-dd' ) AS bsepokeDate, A.USER_ID AS userId, A.BESPOKE_DATE AS bespokeDate, A.BESPOKE_STATUS bespokeStatus, A.PROJECT_ID AS projectId, A.PERIOD_START AS periodStart, A.PERIOD_END AS periodEnd, A.FEESCALE_MONEY AS feescaleMoney, A.FEESCALE_NAME AS feescaleName, A.PAYMENT_TIME AS paymentTime, A.PAYMENT_MONEY AS paymentMoney, B.IDENTITY_CARD AS identityCard, B.REALNAME AS realname, B.SJ AS sj, B.GZZH AS gzzh, B.PHOTOELECTRIC_CARD AS photoelectricCard, B.SEX AS sex, B.BIRTH_DATE AS birthDate, B.STUDENT_ID AS studentId, B.EXAMINE_NUMBER AS examineNumber, B.DEPARTMENT AS department, B.FACULTY AS faculty, C.MEC_NAME AS mecName FROM TSINGHUA_ME_BESPOKE A LEFT JOIN TSINGHUA_USERINFO B ON A.USER_ID=B.ID LEFT JOIN MEC_ITEM C ON A.PROJECT_ID=C.MEC_NUMBER WHERE 1=1 <if test= 'bespokeDateGteJ != null and bespokeDateLteJ != null ' > <if test= 'bespokeDateLteJ != "" and bespokeDateLteJ != ""' > AND A.PAYMENT_TIME <![CDATA[<=]]> to_date(#{bespokeDateLteJ,jdbcType= DATE }, 'yyyy-MM-dd HH24:MI:SS' ) AND A.PAYMENT_TIME <![CDATA[>=]]> to_date(#{bespokeDateGteJ,jdbcType= DATE }, 'yyyy-MM-dd HH24:MI:SS' ) </if> </if> <choose> < when test= 'orderByFiled!=null and orderByFiled!="" and orderBySe!=null and orderBySe!=""' > ORDER BY #{orderByFiled} #{orderBySe} </ when > <otherwise> ORDER BY A.PAYMENT_TIME DESC </otherwise> </choose> </ select > |
最简单的解决办法是将#换为$,但是这样会有sql注入的问题
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 获取排序条件集合
有些勤劳的小伙伴可能就开始写了
?1 2 3 | userOrderSet = [ 'id' , 'id desc' , 'age' , 'age desc' ,.......] scoreOrderSet = [ 'yuwen' , 'yuwen desc' , 'shuxue' , 'shuxue desc' ,.......] ............. |
要是有n多表n多字段可是要急死人
我们使用注解+映射来获取
- 2.3 动态获取集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /** 首先改造实体类,有@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; //更新时间 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | /**工具类来了**/ 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 ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //调用操作一下 //检验动态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); |
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/ClearLoveQ/article/details/98314496
声明
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。