Mybatis动态传入order by问题

吾爱主题 阅读:156 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.作者投稿可能会经我们编辑修改或补充。

【腾讯云】云服务器产品特惠热卖中
搜索
标签列表
    关注我们

    了解等多精彩内容