mybatis使用${}如何避免SQL注入

IT 文章2年前 (2023)发布 小编
0 0 0

学过mybatis的同学应该都知道,为了避免SQL注入,mybatis语句中要尽量使用 #{xxx}来避免SQL注入,而尽量不要使用${xxx},原因也很简单,就是因为${xxx}这样格式的参数会直接参与SQL 编译,该参数内容会直接影响SQL语句结构,从而无法避免注入攻击,而#{xxx} 参数只会作为字符串参数进行拼接,再执行编译,不会影响SQL原本结构。

既然如此,那为何还要有${xxx} 这种简单的占位符呢?原因在于有一种特殊情况,当涉及到动态表名和列名时,只能使用${xxx}这样的参数格式。为了SQL防止注入,我们只能通过手工处理入参来进行防止注入操作。

案例

比较常见的案例就是根据不同的字段进行排序,排序方式也可以动态实现升序和降序。

ad

程序员导航

优网导航旗下整合全网优质开发资源,一站式IT编程学习与工具大全网站

解决方法

以下是一个相关实现mybatis使用${}避免SQL注入的案例方法。

[v_blue]核心思路:针对查询入参的动态字段,将其取值限制在SQL表对应的Entity的字段类,如果动态字段不在Entity内就说明是非法入参[/v_blue]

1)test表

这里假设我们test表有param1,param2,param3这3个字段。

2)TestEntity

该表对应的TestEntity自然也会包含param1,param2,param3这3个属性。

ad

AI 工具导航

优网导航旗下AI工具导航,精选全球千款优质 AI 工具集

3)入参

比如现在根据动态字段进行排序,查询入参如下:

@Data
public class QueryRequest implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 查询字段1
     */
    private String param1;

    /**
     * 排序字段
     */
    private String orderField;

   /**
     * 排序类型
     */
    private String orderType;
}

4)Mapper.xml里的SQL

我们Mapper.xml查询SQL如下:

select * from test 
<where> 
// 这里省略...
</where>
order by ${orderField} ${orderType} 

我们发现这里使用了${orderField}/${orderType} 存在SQL注入风险,如果sortField传一个注入语句那就危险了,因此我们在Service或者Controller层对orderField/orderType的取值要进行限制为param1或param2或param3或asc或desc,即TestEntity中的字段以及排序类型。

5)实现限制方法

我们利用反射写一个通用的限制方法如下(这里还允许升降序的取值限制):

public class DynamicOrderUtils {
    private static final List<String> ORDER_TYPES = Arrays.asList("descend", "ascend", "desc", "asc");

    /**
     * 获取对象可以排序的属性值列表
     *
     * @param object
     * @return
     */
    private static Set<String> getTableFields(Class<?> object) {
        //获取filed数组
        Set<String> resultList = new HashSet<>();
        try {
            Field[] fields = object.getDeclaredFields();
            for (Field field : fields) {
                resultList.add(field.getName());
            }
            return resultList;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultList;
    }

    /**
     * 判断动态order是否是合理
     *
     * @param object
     * @return
     */
    public static boolean isRight(String orderColumn, String orderType, Class<?> object) {
        //先获取所有可用排序属性
        Set<String> columnSet = getTableFields(object);
        return (StringUtils.isBlank(orderColumn) || columnSet.contains(orderColumn)) && (StringUtils.isBlank(orderType) || ORDER_TYPES
            .contains(orderType.toLowerCase()));
    }

}

 6)使用校验

最后我们在Service或者Controller层对orderField/orderType的取值要进行限制,只需调用如下方法:

boolean right = DynamicOrderUtils.isRight(queryRequest.getOrderField(), queryRequest.getOrderType(), TestEntity.class);

如果返回true,说明满足条件,否则你可以抛出异常提示。

ad

免费在线工具导航

优网导航旗下整合全网优质免费、免注册的在线工具导航大全

总结

以上就是mybatis使用${}如何避免SQL注入的全部内容,目前还没有更好的解决方案,如果你有更好的方案,欢迎留言!

© 版权声明

相关文章

暂无评论

暂无评论...