Mybatis动态传入order by问题

Kefira ·
更新时间:2024-11-13
· 992 次阅读

目录

Mybatis动态传入order by

Mybatis order by动态参数防注入

先提及一下Mybatis动态参数

order by 动态参数

解决Order by动态参数注入问题

总结

Mybatis动态传入order by

当Mybatis的mapper文件传入的order by 为动态参数说的时候发现排序无法生效:

像下面这样,在choose when中的order by后的参数是用预编译的方式,用的是#号,这样是可以防止sql注入的问题,但是在传入order by参数的时候无法解析:

<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 ASuserId, A.BESPOKE_DATE ASbespokeDate, A.BESPOKE_STATUSbespokeStatus, A.PROJECT_ID ASprojectId, A.PERIOD_START AS periodStart, A.PERIOD_END ASperiodEnd, 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 获取排序条件集合

有些勤劳的小伙伴可能就开始写了

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); 总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持软件开发网。



BY order mybatis

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章