Mybatis动态字段排序防注入-简单粗暴上代码的方式

一、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、条条大路通罗马,适用于自己项目的才是最好的防注入动态排序。

上一篇:Python海龟turtle画图常见画图代码大全


下一篇:动态改变SVG的颜色