一、Mybatis动态参数说明
参数符号 | 编译 | 安全 | 值 |
#{} | 预编译 | 安全 | ?替换,处理后的值,字符类型都带双引号 |
${} | 未预编译 | 不安全,存在SQL注入问题 | 页面传什么值就是什么值 |
二、order by 动态参数值说明
1、order by后面使用#{} 是无效的,只能使用${}。如果使用${}是会引起SQL注入的。
三、动态参数校验防止SQL注入
1、查询BO对象定义好排序参数
@ApiModelProperty(value = "排序字段") private String column; @ApiModelProperty(value = "排序方式") private String order;
2、自定义校验参数是否非法方法,如果排序字段任一为空,则不排序,排序方式只能是desc或者asc,否则校验排序字段是否合法。
/** * 排序参数是否非法 * * @param column 字段 * @param order 类对象 * @param obj 类对象 * @return true:不排序或不存在非法 */ public static String isParamIllegal(String column, String order, Object obj) { if (StringUtils.isEmpty(column) || StringUtils.isEmpty(order)) { return "true"; } else { if ("desc".equals(order) || "asc".equals(order)) { // 如果不等于则返回false } else { return "order参数非法,请检查!"; } } // 判断排序字段是否存在对应实体中 if (isExistField(column, obj)) { return "true"; } else { return "column参数非法,请检查!"; } }
3、通过将实体对象转为json对象,判断是否属于定义好的参数。
/** * 判断你一个类是否存在某个属性(字段) * * @param field 字段 * @param obj 类对象 * @return true:存在,false:不存在, null:参数不合法 */ public static Boolean isExistField(String field, Object obj) { if (obj == null || StringUtils.isEmpty(field)) { return null; } Object o = JSON.toJSON(obj); JSONObject jsonObj = new JSONObject(); if (o instanceof JSONObject) { jsonObj = (JSONObject) o; } return jsonObj.containsKey(field); }
4、将驼峰字段转换为数据库下划线字段
/** * 将驼峰命名转化成下划线 * * @param para * @return */ public static String camelToUnderline(String para) { if (para.length() < 3) { return para.toLowerCase(); } StringBuilder sb = new StringBuilder(para); int temp = 0;//定位 //从第三个字符开始 避免命名不规范 for (int i = 2; i < para.length(); i++) { if (Character.isUpperCase(para.charAt(i))) { sb.insert(i + temp, "_"); temp += 1; } } return sb.toString().toLowerCase(); }
5、通过校验后再传入查询对象
TestObject testObject = new TestObject (); String msg = CommonUtils.isParamIllegal(testObjectQueryBO.getColumn(), testObjectQueryBO.getOrder(), testObject ); if (!"true".equals(msg)) { return Result.OK(msg); } else { if (StringUtils.isNotBlank(testObjectQueryBO.getColumn())) { testObjectQueryBO.setColumn(oConvertUtils.camelToUnderline(testObjectQueryBO.getColumn())); } }
6、xml代码,如果传入字段不是创建时间,则先按排序字段排序,再按创建时间倒叙排序。
<choose> <when test="testObjectQueryBO.column!=null and testObjectQueryBO.column=='create_time' and testObjectQueryBO.order!=null and testObjectQueryBO.order!=''"> ORDER BY ${testObjectQueryBO.column} ${testObjectQueryBO.order} </when> <otherwise> <if test="testObjectQueryBO.column!=null and testObjectQueryBO.column!='' and testObjectQueryBO.order!=null and testObjectQueryBO.order!=''"> ORDER BY ${testObjectQueryBO.column} ${testObjectQueryBO.order}, create_time DESC </if> </otherwise> </choose>
四、总结
1、动态排序的实现方式有很多,我这种只是其一。我的方法是之前过滤防止传入非法参数,虽然实现方式复杂了一点,但是至少安全。
2、有些人的实现方式是通过判断排序字段是否包含delete、;、等标识判断是否非法。如下:
<if test='sort !=null and sort !="" and !sort.contains(";")'>
order by ${sort}
</if>
3、条条大路通罗马,适用于自己项目的才是最好的防注入动态排序。