JAVA代码审计-url跳转漏洞原理与案例
字数 1671 2025-08-10 19:49:11
Java代码审计:URL跳转漏洞原理与防御指南
一、URL跳转漏洞概述
URL跳转漏洞(也称为URL重定向漏洞)是由于服务端未对传入的跳转地址进行检查和控制,导致攻击者可以构造任意恶意地址,诱导用户跳转至恶意站点。这种漏洞常用于钓鱼攻击,利用用户对可信站点的信任进行欺骗。
漏洞危害
- 钓鱼攻击:诱导用户输入敏感信息
- 绕过安全机制:绕过基于白名单的安全校验
- 内网探测:支持其他协议时可能导致内网信息泄露
- 信任链破坏:从可信站点跳转增加用户信任度
二、漏洞常见触发点
1. 常见触发函数
redirect, redirectUrl, callback, return_url, toUrl, ReturnUrl,
fromUrl, redUrl, request, redirect_to, redirect_url, jump,
jump_to, target, to, goto, link, linkto, domain
2. 常见业务场景
- 登录认证后的跳转
- 用户分享/收藏内容后的跳转
- 跨站点认证/授权后的跳转
- 站内链接点击跳转
- 用户交互页面跳转(如评价、问卷等)
- 业务完成后的跳转(如修改密码后跳转登录页)
三、漏洞代码示例与分析
1. Spring MVC重定向漏洞
漏洞代码1:直接重定向
@GetMapping("/redirect")
public String redirect(@RequestParam("url") String url) {
return "redirect:" + url;
}
问题:直接拼接用户输入的url参数,未做任何校验
漏洞代码2:setHeader重定向
@RequestMapping("/setHeader")
public static void setHeader(HttpServletRequest request, HttpServletResponse response) {
String url = request.getParameter("url");
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301
response.setHeader("Location", url);
}
漏洞代码3:sendRedirect重定向
@RequestMapping("/sendRedirect")
public static void sendRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
String url = request.getParameter("url");
response.sendRedirect(url); // 302
}
2. ModelAndView重定向漏洞
@RequestMapping("/redirect1")
public ModelAndView ModelAndView(HttpServletRequest request, HttpServletResponse response){
String url = request.getParameter("url");
url = "redirect:" + url;
return new ModelAndView(url);
}
3. RedirectAttributes重定向
@RequestMapping("/redirect4")
public String RedirectAttributes(RedirectAttributes redirectAttributes, String url){
redirectAttributes.addAttribute("id", url);
return "redirect:/index";
}
四、安全防护方案
1. 使用RequestDispatcher转发(安全)
@RequestMapping("/forward")
public static void forward(HttpServletRequest request, HttpServletResponse response) {
String url = request.getParameter("url");
RequestDispatcher rd = request.getRequestDispatcher(url);
try {
rd.forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
优点:只能跳转同一web应用内的路径,不会改变浏览器地址栏URL
2. 白名单校验
@RequestMapping("/sendRedirect/sec")
public void sendRedirect_seccode(HttpServletRequest request, HttpServletResponse response) throws IOException {
String url = request.getParameter("url");
if (SecurityUtil.checkURL(url) == null) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.getWriter().write("url forbidden");
return;
}
response.sendRedirect(url);
}
public static boolean isWhite(String url) {
List<String> url_list = new ArrayList<String>();
url_list.add("baidu.com");
url_list.add("www.baidu.com");
url_list.add("oa.baidu.com");
URI uri = null;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
System.out.print(e);
}
String host = uri.getHost().toLowerCase();
return url_list.contains(host);
}
3. 其他防护措施
- 固定跳转目标URL(不可控)
- 给用户展示安全风险提示,由用户确认跳转
- 记录跳转日志用于审计
五、漏洞利用与绕过技术
1. 直接跳转
https://victim.com/redirect?url=http://evil.com
2. 协议一致性绕过
https://victim.com/redirect?url=https://evil.com
3. 域名字符串检测欺骗
https://victim.com/redirect?url=http://evil.com/victim.com
4. 可信站多次重定向
https://victim.com/redirect?url=https://trusted.com/redirect?url=evil.com
5. 特殊字符绕过技术
10种常见绕过方式:
- 单斜线"/"绕过:
/www.evil.com - 缺少协议绕过:
//www.evil.com - 多斜线"/"前缀绕过:
///www.evil.com - "@"符号绕过:
https://victim.com@www.evil.com - 反斜线""绕过:
https://www.evil.com\www.victim.com - "#"符号绕过:
https://www.evil.com#www.victim.com - "?"号绕过:
https://www.evil.com?www.victim.com - 双反斜线绕过:
https://www.evil.com\\www.victim.com - "."字符绕过:
.evil.com(跳转到evil.com) - 重复特殊字符:
////www.evil.com//..
6. 其他绕过思路
- 跳转到IP地址而非域名
- 使用IPv6地址
- IP地址的十进制/八进制/十六进制表示
- 更换协议(ftp、gopher等)
- 借鉴SSRF绕过技巧
六、审计方法与防御建议
1. 审计关键点
- 查找所有重定向相关函数调用
- 检查重定向目标是否用户可控
- 验证是否存在白名单校验
- 检查校验逻辑是否可绕过
2. 防御建议
- 使用白名单校验重定向目标
- 固定跳转目标URL(不可控)
- 使用RequestDispatcher进行服务端跳转
- 对用户展示跳转风险提示
- 记录所有跳转操作日志
- 定期进行安全审计和渗透测试
七、实际案例分析
案例1:eyoucms任意URL跳转
漏洞点:logout()函数中referurl参数未校验
$referurl = input('referurl');
redirect($referurl);
利用:构造恶意referurl参数实现任意跳转
案例2:开放端口导致的URL跳转
漏洞点:开放端口接收特定数据可导致访问任意URL
案例3:Spring MVC视图操纵
漏洞点:模板路径拼接用户输入
@GetMapping("/path")
public String path(@RequestParam String lang) {
return "user/" + lang + "/welcome"; // 模板路径污染
}
POC:使用Thymeleaf SSTI payload
__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc.exe%22).getInputStream()).next()%7d__::.x
八、总结
URL跳转漏洞虽然看似简单,但危害严重且利用方式多样。开发人员应:
- 避免直接使用用户输入作为跳转目标
- 实施严格的白名单校验机制
- 考虑使用服务端跳转替代客户端重定向
- 对用户进行风险提示
- 定期进行安全审计
安全人员在进行代码审计时应重点关注所有重定向相关函数,验证目标URL的校验逻辑是否完备,是否存在绕过可能。