Java代码审计实战:URL跳转漏洞深度解析

发布于:2025-09-14 ⋅ 阅读:(16) ⋅ 点赞:(0)

Java代码审计实战:URL跳转漏洞深度解析

URL跳转(Open Redirect)漏洞,是指应用程序将用户提交的URL参数作为重定向目标,但没有对URL进行严格的校验,从而使得攻击者能够构造恶意链接,将用户重定向到钓鱼网站或其他恶意页面。

1. 漏洞的本质:服务器成了攻击者的帮凶

URL跳转漏洞的根本原因在于,应用程序过于信任用户输入,直接将用户提供的URL参数传递给了重定向函数,例如 response.sendRedirect()。这使得攻击者能够利用一个可信的域名(即存在漏洞的网站)来发起钓鱼攻击,大大增加了欺骗性。

经典案例:直接使用用户提供的URL

许多Web应用在登录、支付或某些业务流程结束后,会提供一个 redirectreturnUrl 参数,让用户跳转回之前的页面。如果开发者直接使用这个参数,就可能导致漏洞。

Java

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Controller
public class RedirectController {

    @GetMapping("/redirect_vulnerable")
    public void redirectVulnerable(@RequestParam("url") String url, HttpServletResponse response) throws IOException {
        // 危险:直接重定向到用户提供的URL
        response.sendRedirect(url);
    }
}

漏洞分析:

这段代码看似无害,但如果攻击者构造一个恶意链接,例如:

http://yourdomain.com/redirect_vulnerable?url=http://phishing-site.com/login

当用户点击这个链接后,服务器会无条件地将用户重定向到 http://phishing-site.com/login。攻击者可以利用你的可信域名来发起钓鱼攻击,欺骗用户输入敏感信息。

2. 进阶陷阱:常见的绕过技巧

许多开发者会尝试通过一些简单的校验来防御,但这些防御措施往往存在缺陷,极易被攻击者绕过。

案例一:黑名单校验的弱点

开发者可能会建立一个“黑名单”,禁止跳转到某些特定的域名。

@GetMapping("/redirect_blacklist")
public void redirectBlacklist(@RequestParam("url") String url, HttpServletResponse response) throws IOException {
    // 危险:不安全的黑名单校验
    if (url.startsWith("http://malicious.com")) {
        // ...
        return;
    }
    response.sendRedirect(url);
}

绕过技巧:

攻击者可以利用URL的解析特性来绕过这种简单的 startsWith 校验。

  • 利用 @ 符号http://yourdomain.com/redirect_blacklist?url=http://www.yourdomain.com@phishing-site.com

    • 漏洞分析@ 符号后面的域名是真正的跳转目标。浏览器会认为 www.yourdomain.com 是用户名,而 phishing-site.com 才是主机名。校验通过。

  • 利用URL路径http://yourdomain.com/redirect_blacklist?url=http://www.yourdomain.com.phishing-site.com

    • 漏洞分析startsWith 校验无法识别 yourdomain.com.phishing-site.com 是一个不同的域名。

案例二:白名单校验的缺陷

开发者可能会建立一个“白名单”,只允许跳转到本站或指定的几个域名。但如果校验逻辑存在缺陷,也可能被绕过。

@GetMapping("/redirect_whitelist")
public void redirectWhitelist(@RequestParam("url") String url, HttpServletResponse response) throws IOException {
    // 危险:不安全的白名单校验
    if (url.startsWith("http://yourdomain.com") || url.startsWith("https://yourdomain.com")) {
        response.sendRedirect(url);
    } else {
        response.sendRedirect("/index");
    }
}

绕过技巧:

攻击者可以利用URL的各种特性来绕过 startsWith 校验。

  • // 绕过http://yourdomain.com/redirect_whitelist?url=//phishing-site.com

    • 漏洞分析:URL中双斜线 // 后面的内容会被浏览器解析为域名,从而跳转到 phishing-site.com

  • #? 绕过http://yourdomain.com/redirect_whitelist?url=/path/to/page#phishing-site.com

    • 漏洞分析:URL中的 #? 后面的内容通常被认为是片段标识符或查询参数,不影响主路径。但某些服务器在处理重定向时可能忽略这些符号,导致URL被解析为 yourdomain.com/path/to/page#phishing-site.com,浏览器会尝试跳转到phishing-site.com

3. 审计与加固:构建多层防御体系

防御URL跳转漏洞的核心在于:永远不要相信用户提供的URL,并使用白名单机制进行严格的域名校验

审计重点:

  • 寻找重定向入口:在代码库中搜索 response.sendRedirect()return "redirect:"header("Location: ...") 等关键字。

  • 追踪数据流:检查重定向的目标URL是否直接或间接来自用户输入(如 request.getParameter())。

安全修复方案:

  • 使用白名单机制:最安全且推荐的防御措施。只允许跳转到预先定义好的、可信的域名。

     
    @GetMapping("/redirect_safe")
    public void redirectSafe(@RequestParam("url") String url, HttpServletResponse response) throws IOException {
        String safeDomain = "yourdomain.com";
        // 校验URL的域名
        if (url != null && url.startsWith("http://") || url.startsWith("https://")) {
            // 解析URL
            java.net.URL parsedUrl = new java.net.URL(url);
            String host = parsedUrl.getHost();
            if (host.equals(safeDomain) || host.endsWith("." + safeDomain)) {
                // 如果是本站或子域名,允许跳转
                response.sendRedirect(url);
            } else {
                // 非法域名,重定向到默认首页
                response.sendRedirect("/index");
            }
        } else if (url != null && url.startsWith("/")) {
            // 允许相对路径跳转
            response.sendRedirect(url);
        } else {
            response.sendRedirect("/index");
        }
    }
    

    这个示例中,我们使用了 java.net.URL 类来解析URL,获取其主机名,并与白名单进行严格比对,从而有效防止了各种绕过技巧。

  • 禁止外链跳转:如果业务需求允许,只允许用户进行站内跳转。

    • 使用相对路径:将所有重定向目标都限定为相对路径,这样无论用户输入什么,都会被解析为站内地址。

    • 在重定向前验证:在重定向前,手动检查目标URL是否是相对路径。

  • 使用跳转前的中间页提示:当需要跳转到外部链接时,先显示一个中间页,明确提示用户即将离开本站,并显示目标URL,让用户自行确认。