mybatis动态传入order by(排序字段) 和 sort(排序方式) 防止注入

mybatis动态传入order by(排序字段) 和 sort(排序方式) 只能使用KaTeX parse error: Expected ‘EOF’, got ‘#’ at position 8: {}传参方式,#{}传参无效。但众所周知使用{}传参会有SQL注入问题,上网查了一下很多都说鱼与熊掌不可兼得,接下来介绍一下如何使用动态传参且能够防止注入的方法。

一、mybatis的两种传参方式#{}和${}

1. #传参

1.1 # 是通过prepareStatement的预编译的,会对自动传入的数据加一个单引号。
如:order by #{orderBy},如果传入的时间是 ,则会被解析为 order by ‘update_time’ (这样排序是无效的,这也是为什么不能用#号传参的原因)。
1.2 #方式能够很大程度防止sql注入

2. $传参

$ 方式会传入一个不改变的字符串,不能够防止注入
如:order by #{orderBy},如果传入的时间是 ,则会被解析为 order by update_time

因此,能用#号就别用KaTeX parse error: Expected 'EOF', got '#' at position 40: …字段和方式这样的情况,不能使用#̲号传参了,使用传参又希望能够防止注入保证安全。下面介绍一下我的解决方式。

二、$传参如何防止注入

使用枚举的方式可以解决这个问题,简单的说就是提前定义好我们的表名、排序字段和排序方式有哪些。将我们需要用到的表名、排序字段和排序方式这些内容定义到单独的枚举类或者常量定义类中。
下面介绍两种方式:

2.1 在业务代码中判断防止注入:

在业务代码中进行判断,不在此范围的我就直接按默认方式处理,这样就可以过滤掉不规范的参数和sql的注入代码。
关键代码:
仅以开始时间和更新时间的排序介绍,可根据实际需求的情况添加其他业务字段,

// 默认开始时间倒序 
param.setOrderBy("begin_time");
param.setSort("DESC");  	

if (StringUtils.isNotEmpty(param.getOrderBy())) {
    switch (param.getOrderBy()) {
        case "updateTime":
            param.setOrderBy("update_time");
            break;
        default:
            param.setOrderBy("begin_time");
    }
} 

// 如果是升序,就重新设置为升序
if("ascending".equals(param.getSort())) {
    param.setSort("ASC");
} 

处理过后都是我们可控的属性内容,就可以直接使用$传参了,如:

SELECT <include refid="Base_Column_List"/> 
FROM alarm_list_info_view as m
<where>
        m.status = 0
</where>
order by ${param.orderBy}  ${param.sort}

2.1 在mybatis的xml文件中判断枚举防注入

关键代码:

SELECT <include refid="Base_Column_List"/> 
FROM alarm_list_info_view as m
<where>
     <if test="param.orderBy== 'begin_time'">
    	order by begin_time
     </if>
     <if test="param.orderBy== 'update_time'">
        order by update_time
     </if>
</where>

// 或者这样 总之先保证是我们需要的排序字段和方式 一般字段也不会太多 不够可以添加 
SELECT * FROM alarm_list_info_view as m
<choose>    
	 <when test="(orderBy=='begin_time' or orderBy=='update_time') and (sort=='desc' or sort=='asc')">      
	  	  order by ${orderBy}   ${sort}  
	 </when>    
     <otherwise>    
  		  order by updateTime   desc
     </otherwise>    
</choose>

按照这个思路就能完美解决了,各位大佬有别的解法请求指教。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
如果前端不传入数据库字段名,只传入排序方式,那么你可以在后端定义好所有可以被排序字段名及其对应的数据库字段名,前端只需要传入一个排序方式和一个可排序字段名的标识符,后端就可以根据标识符找到对应的数据库字段名,再将它们填充到 SQL 语句中。 以下是一个示例: 假设你有一个名为 `User` 的实体类,其中有三个属性:`id`、`name` 和 `age`。你要根据这三个属性进行排序,前端只会传入排序方式(升序或降序)和一个标识符,表示需要排序的属性。你可以在后端定义一个映射表,将标识符和数据库字段名对应起来,如下所示: ```java Map<String, String> fieldMap = new HashMap<>(); fieldMap.put("id", "id"); fieldMap.put("name", "name"); fieldMap.put("age", "age"); ``` 然后,当收到前端的请求时,你可以按照以下步骤进行处理: 1. 获取前端传来的排序方式排序字段标识符: ```java String sortField = request.getParameter("sortField"); String sortOrder = request.getParameter("sortOrder"); ``` 2. 根据排序字段标识符获取对应的数据库字段名: ```java String dbFieldName = fieldMap.get(sortField); ``` 3. 将排序方式和数据库字段名填充到 SQL 语句中,例如: ```java String sql = "SELECT * FROM user ORDER BY " + dbFieldName + " " + sortOrder; ``` 在上述代码中,`dbFieldName` 是根据标识符从映射表中获取到的数据库字段名,`sortOrder` 是前端传来的排序方式(ASC 或 DESC),最后将它们填充到 SQL 语句中,就可以得到一个带有排序条件的 SQL 语句。 需要注意的是,这种设计方式要求后端必须定义好所有可排序字段名及其对应的数据库字段名,并且前端传来的标识符必须是合法的,否则就会导致 SQL 语句构建出错。因此,在设计时需要慎重考虑,避免出现漏洞或错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值