URI通过编码两次绕过参数验证

参数名双重编码绕过

在 Spring Boot 或其他 Web 框架中,双重 URL 编码绕过参数验证 是一个常见的安全问题,主要与 解析顺序、不同组件的解码逻辑 以及 不一致的 URL 规范 有关。以下是详细分析:


1. 为什么双重编码可以绕过参数名的判断规则?

通常,Web 应用中的 URL 解析涉及多个组件(如浏览器、Web 服务器、应用服务器),它们可能在 不同阶段进行 URL 解码,导致安全检查与实际执行路径不一致。例如:

  • 应用服务器(如 Tomcat、Nginx) 可能先解码一次,再把请求交给 Spring Boot 处理。
  • Spring MVC 处理 @RequestParam 或 @PathVariable 时会再解码一次。
  • 如果某些安全检查(黑名单规则)在第一步之前执行,攻击者就可以利用双重编码绕过这些检查。

绕过方式示例

假设有一个 Web 应用,它会拦截 ../ 以防止目录遍历攻击:

 

1

@GetMapping("/files/{filename}")

2

public String getFile(@PathVariable String filename) {

3

if (filename.contains("../")) {

4

return "非法路径";

5

}

6

return "读取文件:" + filename;

7

}

如果攻击者直接访问:

GET /files/../etc/passwd

服务器会发现 ../,然后拦截请求,返回 "非法路径"。

但如果攻击者使用双重编码呢?
GET /files/%252E%252E%252Fetc/passwd

解码过程:

  1. Spring 解析 PathVariable 时会执行一次解码

    %252E%252E%252F  →  %2E%2E%2F
    
  2. 应用逻辑执行检查(但此时 ../ 仍然是 %2E%2E%2F,不会被拦截)。

  3. 服务器读取文件时可能再解码一次

    %2E%2E%2F  →  ../
    
  4. 最终导致目录遍历攻击生效!


2. 不同阶段的 URL 解码导致绕过

不同 Web 组件的 URL 解析顺序不同,会导致安全检查无效。以下是常见的 URL 解析顺序:

  1. 浏览器或攻击者构造 URL
    • 可能使用单重或双重编码。
  2. Web 服务器(Nginx/Tomcat)
    • 可能解码 一次(部分服务器会直接解析 URL)。
  3. Spring Boot 应用
    • @RequestParam / @PathVariable 解析时会自动解码一次。
  4. 内部文件读取或 API 处理
    • 可能解码第二次。

如果检查逻辑在第一层解码之前执行,而最终访问路径的解析在第二层解码之后发生,就可能导致绕过。


3. 其他常见的双重编码绕过方式

(1) /(斜杠)绕过

某些 Web 应用可能会阻止 / 作为路径访问符号:

  • 直接访问 /admin/config 被拦截。
  • 但 GET /admin%2Fconfig 可能仍然有效(因为 %2F 可能被后端解码为 /)。

变种:

/admin%252Fconfig  →  /admin%2Fconfig  →  /admin/config

可能绕过安全检查。


(2) SQL 注入绕过

有些 Web 应用会检查 SQL 关键字,但如果只检查一次解码后的参数,可能被绕过:

?id=%2527%2520OR%25201%253D1%2520--%2520

解码:

  1. %2527%2520OR%25201%253D1%2520--%2520 → %27 OR 1=1 --
  2. %27 OR 1=1 -- → ' OR 1=1 -- (SQL 注入生效)

(3) 认证绕过

如果 API 通过 @RequestParam 获取 user

 

1

@GetMapping("/api")

2

public String api(@RequestParam String user) {

3

if ("admin".equals(user)) {

4

return "无权访问";

5

}

6

return "Hello " + user;

7

}

攻击者使用:

GET /api?user=%2561%2564%256D%2569%256E

解码:

  1. %2561%2564%256D%2569%256E → %61%64%6D%69%6E
  2. %61%64%6D%69%6E → admin

如果检查发生在第一步前,就可能绕过认证。


4. 如何防止双重编码绕过?

(1) 统一解码

确保所有 输入验证 和 业务逻辑 都基于 最终解码后的值

 

1

import java.net.URLDecoder;

2

import java.nio.charset.StandardCharsets;

3

4

@GetMapping("/files/{filename}")

5

public String getFile(@PathVariable String filename) {

6

// 先完整解码

7

String decoded = URLDecoder.decode(filename, StandardCharsets.UTF_8);

8

9

// 统一检查解码后的字符串

10

if (decoded.contains("../")) {

11

return "非法路径";

12

}

13

return "读取文件:" + decoded;

14

}

🔹 这样,即使攻击者使用 %252E%252E%252F,解码后仍然会被拦截


(2) 服务器层面限制

  • Nginx / Tomcat

    配置中禁止双重编码:

     
      

    1

    location / {

    2

    set $block_extensions "..";

    3

    if ($request_uri ~ $block_extensions) {

    4

    return 403;

    5

    }

    6

    }
  • Tomcat 关闭二次解码

     
      

    1

    server.tomcat.relaxed-query-chars=<>[]^`{|}

    2

    server.tomcat.relaxed-path-chars=<>[]^`{|}

(3) 使用 WAF(Web 应用防火墙)

例如:

  • ModSecurity 规则:

    SecRule ARGS "@rx %25[0-9a-fA-F]{2}" "id:1001,phase:2,deny,msg:'Double URL Encoding Attack'"
    

    阻止

    %%
    

    形式的编码。


5. 总结

攻击手法原理防御方案
双重编码先绕过检查,再解码后攻击统一解码并检查
路径遍历%252E%252E%252F 变成 ../过滤最终解码后的值
SQL 注入%2527 OR 1=1 -- 变成 ' OR 1=1 --使用预编译SQL
认证绕过user=%2561%2564%256D%2569%256E 变成 admin统一编码解析

双重编码绕过验证的关键在于 安全检查和实际解析的解码顺序不一致,所以最好的方法是: ✅ 先解码,再校验!
✅ 尽量避免多个组件对 URL 进行不同解析!
✅ 使用 Web 防火墙(WAF)等安全措施!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值