任意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.comgetHost()返回: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的域名检查
总结
- 使用
getHost()方法进行URL跳转校验时,必须考虑反斜线和井号的绕过问题 - JDK版本差异会影响安全校验的结果,不能依赖运行环境的JDK版本
- 完整的解决方案应包含对特殊字符的预处理
- 线上环境的JDK升级需谨慎,应在代码层面做好防护