URL跳转漏洞(开放重定向漏洞)发生在Web应用程序未经验证地将用户重定向到第三方URL时。该漏洞允许攻击者构造恶意链接,将用户从可信网站重定向到钓鱼网站或恶意内容页面。
核心问题:应用程序将用户控制的输入直接用于重定向操作,未进行安全验证:
2. 现象
典型漏洞表现:
# 包含重定向参数的可疑URL
https://trusted-site.com/login?redirect=https://evil-phishing.com
http://bank.com/oauth?return_url=ftp://attacker.net
https://app.com/share?url=javascript:alert(document.cookie)
漏洞特征:
- URL中包含
redirect
、return
、url
等参数
- 302状态码或HTML meta刷新跳转
- 跳转后地址与当前域名不相关
- 出现异常协议(如
data:
、ftp:
)或伪协议
3. 漏洞危害
风险类型 |
具体危害 |
案例说明 |
钓鱼攻击 |
窃取凭证/财务信息 |
伪造银行登录页窃取账号密码 |
恶意软件分发 |
诱导下载木马/勒索软件 |
"系统更新"提示下载带毒程序 |
信任欺骗 |
利用可信域名背书 |
https://company.com -> https://company-com.fake/login |
绕过检测 |
规避安全防护机制 |
通过可信站点中转恶意链接 |
存储型XSS |
配合脚本注入攻击 |
redirectUrl=data:text/html,alert(1) |
4. 黑盒渗透测试方法
4.1 基础探测
GET /login?redirect=http://evil.com HTTP/1.1
Host: target.com
4.2 测试Payload清单
测试类型 |
测试Payload |
外部域名 |
?url=https://attacker.com |
特殊协议 |
?forward=ftp://evil.net |
JS伪协议 |
?target=javascript:alert(document.domain) |
编码绕过 |
?jump=https%3A%2F%2Fattacker.com |
双重编码 |
?return=%252F%252Fevil.com |
IP地址 |
?to=http://192.168.1.1 |
目录穿越 |
?next=/../../../../etc/passwd |
空字节注入 |
?url=https://trusted.com .evil.com |
4.3 Burp Suite自动化
# 使用Burp Intruder测试参数
1. 设置参数位置:`redirect=`[插入点]
2. 导入Payload列表:
http://attacker.com
javascript:alert(1)
data:text/html,<script>malicious</script>
/../../etc/passwd
3. 检查响应中的`Location`头
5. Java白盒审计指南
5.1 审计流程
5.2 关键审计点
-
定位危险方法:
// 正则搜索模式
(sendRedirect|setHeader\(\"Location\")|ModelAndView\(\"redirect:)
-
回溯数据流:
// 示例:Spring MVC控制器
@GetMapping("/redirect")
public String redirect(@RequestParam String path) {
// 跟踪path参数来源
return "redirect:" + path;
}
-
验证防护逻辑:
- 白名单域名检查
- 协议限制(仅允许http/https)
- URL规范化处理
- 路径合法性验证
6. Java中的关键代码
6.1 危险重定向方法
方法类型 |
危险代码示例 |
Servlet API |
response.sendRedirect(untrustedUrl); |
Location Header |
response.setHeader("Location", inputUrl); |
Spring Redirect |
return "redirect:" + request.getParam("url"); |
ModelAndView |
new ModelAndView("redirect:" + target); |
RedirectView |
new RedirectView(userControlledUrl); |
6.2 安全重定向示例
// 基于白名单的安全重定向
public void safeRedirect(HttpServletResponse response, String input) {
final Set<String> ALLOWED_DOMAINS = Set.of("trusted.com", "partner.net");
try {
URI uri = new URI(input);
// 验证协议
if(!List.of("http", "https").contains(uri.getScheme())) {
response.sendError(400, "Invalid scheme");
return;
}
// 验证域名
if(!ALLOWED_DOMAINS.contains(uri.getHost())) {
response.sendRedirect("/default");
return;
}
// 执行安全的重定向
response.sendRedirect(uri.toString());
} catch (URISyntaxException e) {
response.sendError(400, "Invalid URL");
}
}
7. PHP中的关键代码
危险重定向函数:
<?php
// 高危重定向函数
header("Location: " . $_GET['url']);
// 不安全的重定向方式
$url = $_POST['redirect'];
echo "<meta http-equiv='refresh' content='0;url=$url'>";
// 危险的重定向实现
die(header("Location: http://" . $_SERVER['HTTP_HOST'] . "/" . $_REQUEST['page']));
安全重定向实现:
<?php
$validRedirects = [
'/dashboard' => true,
'/profile' => true,
'/settings' => true
];
$target = $_GET['target'] ?? '/default';
// 白名单验证
if(isset($validRedirects[$target])) {
header("Location: $target");
} else {
header("Location: /invalid");
}
8. Java漏洞代码
漏洞特征代码:
// 模式1:直接使用用户输入
public void unsafeRedirect1(HttpServletRequest request, HttpServletResponse response) {
String target = request.getParameter("url");
response.sendRedirect(target); // 高危!
}
// 模式2:路径拼接漏洞
public ModelAndView unsafeRedirect2(String section) {
return new ModelAndView("redirect:/user/" + section);
// 若section="../../admin" 会导致路径穿越
}
// 模式3:未验证的Spring重定向
@GetMapping("/oauth/callback")
public String callback(@RequestParam String redirect_uri, String code) {
return "redirect:" + redirect_uri + "?code=" + code;
// OAuth授权码泄露风险
}
// 模式4:协议控制漏洞
public void protocolRedirect(String url) {
if(url.startsWith("http")) { // 仅检查前缀不安全
response.sendRedirect(url);
// 允许http://attacker.com或http://localhost:[email protected]
}
}
漏洞修复要点:
- 白名单校验:建立可跳转域名/路径白名单
- 协议过滤:仅允许http/https协议
- URL规范化:使用
URI
类解析标准化URL
- 域名验证:验证目标域名是否在可信列表
- 相对路径处理:禁止以
../
开头的相对路径
9.实战
redirect
// 满足参数url可控,且未做限制
public String vul(String url) {
return "redirect:" + url;
}
没有任何限制,可以直接随意跳转
ModelAndView
// ModelAndView
public ModelAndView vul2(String url) {
return new ModelAndView("redirect://" + url);
}
没有任何限制,同样随意跳转
response.sendRedirect
// response.sendRedirect
public void vul3(String url, HttpServletResponse response) throws IOException {
response.sendRedirect(url);
}
没有任何限制,同样随意跳转
10.安全代码
白名单模式
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();
System.out.println(host);
return url_list.contains(host);
}
不在范围内的均不能正确跳转
原文始发于微信公众号(今木安全):URL跳转漏洞-原理到实战
评论