任意URL跳转漏洞修复与JDK中getHost()方法之间的坑
字数 980 2025-08-18 11:37:57

Java中URL跳转漏洞修复与getHost()方法的陷阱

任意URL跳转漏洞概述

任意URL跳转漏洞是指服务端未对传入的跳转URL变量进行检查和控制,导致攻击者可以构造恶意地址,诱导用户跳转到恶意网站。由于跳转是从可信站点发起的,用户容易信任,因此这类漏洞常被用于钓鱼攻击。

常见修复方法

最常见的修复方法是校验传入的跳转URL参数值,判断是否为预期域名。Java中的典型实现如下:

String url = request.getParameter("returnUrl");
String host = "";
try {
    host = new URL(url).getHost();
} catch (MalformedURLException e) {
    e.printStackTrace();
}
if (host.endsWith(".bbb.com")) {
    // 允许跳转
} else {
    // 拒绝跳转,报错
}

getHost()方法的潜在问题

问题一:反斜线绕过

漏洞原理

  • 当URL中包含反斜线(\)时,getHost()方法会错误解析
  • 例如:http://www.aaa.com\www.bbb.com
    • getHost()返回:www.bbb.com
    • 实际浏览器跳转:www.aaa.com/www.bbb.com

测试代码

public class Main {
    public static void main(String[] args) {
        String url = "https://www.aaa.com\\www.bbb.com?x=123";
        String host = "";
        try {
            host = new URL(url).getHost();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        System.out.println("host---"+host);
        System.out.println("url---"+url);
    }
}

输出结果

host---www.bbb.com
url---https://www.aaa.com\www.bbb.com?x=123

问题二:JDK版本差异对井号(#)的处理

漏洞表现

  • 对于URL:https://www.aaa.com#www.bbb.com?x=123
  • 高版本JDK(1.8.0_181+/1.7.0_161+):getHost()返回www.aaa.com
  • 低版本JDK(如1.6.0_45, 1.7.0_71, 1.8.0_25):getHost()返回www.aaa.com#www.bbb.com

根本原因

  • 低版本URLStreamHandler.java未正确处理URL中#出现在/?之前的情况
  • 高版本增加了对#位置的判断

测试结果对比

  • 低版本JDK:host值包含#及其后部分
  • 高版本JDK:host值正确截取到#

安全修复方案

综合上述问题,安全的实现应包含以下处理:

String url = request.getParameter("returnUrl");
String host = "";
try {
    // 替换掉反斜线和井号
    url = url.replaceAll("\\\\", "/").replaceAll("#", "");
    host = new URL(url).getHost();
} catch (MalformedURLException e) {
    e.printStackTrace();
}
if (host.endsWith(".bbb.com")) {
    // 允许跳转
} else {
    // 拒绝跳转
}

真实案例

某网站存在漏洞,可通过以下方式绕过:

  • target参数设置为URL编码后的https://www.baidu.com#www.bbb.com?x=123
  • 网站会302跳转到百度,绕过了对bbb.com的域名检查

总结

  1. 使用getHost()方法进行URL跳转校验时,必须考虑反斜线和井号的绕过问题
  2. JDK版本差异会影响安全校验的结果,不能依赖运行环境的JDK版本
  3. 完整的解决方案应包含对特殊字符的预处理
  4. 线上环境的JDK升级需谨慎,应在代码层面做好防护
Java中URL跳转漏洞修复与getHost()方法的陷阱 任意URL跳转漏洞概述 任意URL跳转漏洞是指服务端未对传入的跳转URL变量进行检查和控制,导致攻击者可以构造恶意地址,诱导用户跳转到恶意网站。由于跳转是从可信站点发起的,用户容易信任,因此这类漏洞常被用于钓鱼攻击。 常见修复方法 最常见的修复方法是校验传入的跳转URL参数值,判断是否为预期域名。Java中的典型实现如下: getHost()方法的潜在问题 问题一:反斜线绕过 漏洞原理 : 当URL中包含反斜线( \ )时, getHost() 方法会错误解析 例如: http://www.aaa.com\www.bbb.com getHost() 返回: www.bbb.com 实际浏览器跳转: www.aaa.com/www.bbb.com 测试代码 : 输出结果 : 问题二:JDK版本差异对井号(#)的处理 漏洞表现 : 对于URL: https://www.aaa.com#www.bbb.com?x=123 高版本JDK(1.8.0_ 181+/1.7.0_ 161+): getHost() 返回 www.aaa.com 低版本JDK(如1.6.0_ 45, 1.7.0_ 71, 1.8.0_ 25): getHost() 返回 www.aaa.com#www.bbb.com 根本原因 : 低版本 URLStreamHandler.java 未正确处理URL中 # 出现在 / 或 ? 之前的情况 高版本增加了对 # 位置的判断 测试结果对比 : 低版本JDK:host值包含 # 及其后部分 高版本JDK:host值正确截取到 # 前 安全修复方案 综合上述问题,安全的实现应包含以下处理: 真实案例 某网站存在漏洞,可通过以下方式绕过: 将 target 参数设置为URL编码后的 https://www.baidu.com#www.bbb.com?x=123 网站会302跳转到百度,绕过了对 bbb.com 的域名检查 总结 使用 getHost() 方法进行URL跳转校验时,必须考虑反斜线和井号的绕过问题 JDK版本差异会影响安全校验的结果,不能依赖运行环境的JDK版本 完整的解决方案应包含对特殊字符的预处理 线上环境的JDK升级需谨慎,应在代码层面做好防护