目录
(一)URL 跳转漏洞简介
(二)URL 重定向
1.通过 ModelAndView 方式
2.通过返回 String 方式
3.使用 sendRedirect 方式
4.使用 RedirectAttributes 方式
5.通过设置 Header 来进行跳转
(三)URL 跳转漏洞审计
(四)修复
小结
(一)URL 跳转漏洞简介
URL 跳转漏洞也叫作 URL 重定向漏洞,由于服务端未对传入的跳转地址进行检查和控制,从而导致攻击者可以构造任意一个恶意地址,诱导用户跳转至恶意站点。因为是从用户可信站点跳转出去的,用户会比较信任该站点,所以 URL 跳转漏洞常用于钓鱼攻击,通过转到攻击者精心构造的恶意网站来欺骗用户输入信息,从而盗取用户的账号和密码等敏感信息,更甚者会欺骗用户进行金钱交易

攻击者首先精心构造一个钓鱼站点 A ,然后利用 URL 跳转漏洞修改目的跳转地址,使原本应跳转到可信任站点 C 的地址变成钓鱼站点 A 。由于用户信任站点B,而钓鱼站点 A 又是从可信任站点 B 中重定向的,因此可能对钓鱼站点 A 同样信任。用户一旦用户输入相关的敏感信息,就可能被攻击者窃取。
(二)URL 重定向
Spring MVC 中使用重定向的场景很多,一般有以下几种方法来进行 URL 重定向
1.通过 ModelAndView 方式
public ModelAndView testforward(HttpServletRequest req, HttpServletResponse resp) throws Exception {
String url =req.getParameter("url");
String url = "redirect: "+url;
return new ModelAndView(url);
}
2.通过返回 String 方式
public String redirect(@RequestParam("url") String url) {
return "redirect:" + url;
}
3.使用 sendRedirect 方式
public static void sendRedirect(HttpServletRequest request, HttpServletResponse response) throws
IOException{
String url = request.getParameter("url");
response.sendRedirect(url);
}
4.使用 RedirectAttributes 方式
@RequestMapping("/RedirectAttributes")
public String test4(RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute("id","2");
return "redirect:/test/index";
}
“ @RequestMapping("/RedirectAttributes") ”在方法前面要说明 URL 访问是通过http://192.168.88.2:8080/RedirectAttributes 来访问,代码中“return "redirect:/test/index";”,就会重定向到 http://192.168.88.2:8080/test/index 这 个 URL ,通过“ redirectAttributes.addAttribute("id","2") ”传递了 id=2 这个参数,所以最终访问的其实是 http://192.168.88.2:8080/test/index?id=2 这个 URL 地址。 RequestMapping 的执行效果如图 1 -2 所示

5.通过设置 Header 来进行跳转
public static void setHeader(HttpServletRequest request, HttpServletResponse response){
String url = request.getParameter("url");
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
response.setHeader("Location", url);
}
redirect
sendRedirect
ModelAndView
Location
addAttribute
- 开发人员不具备安全意识,编写代码时没有考虑任意 URL 跳转漏洞;
String url = request.getParameter("url");
response.sendRedirect(url);
- 开发人员具有一定的安全意识,但是编写代码时考虑不够缜密,采用取关键字、取后缀等方法简单判断要跳转的地址,使代码逻辑可被绕过;
String trustUrl = "www.domain.com";
String url = request.getParameter("returnUrl");
if (url.substring(0,trustUrl.length()) == trustUrl)
{
response.sendRedirect(url);
}
此处开发者认为只要判定传入的 URL 地址前若干位为其事先设置好的白名单的地址,则认为该地址是安全和可信的地址,并执行跳转。但对于上述字符串检测操作,均可以采用欺骗手法或者配合 URL 的各种特性符号绕过判断,如下所示
www.test.com/?redirectUrl=http://www.domain.com.hacker.net。
www.test.com/?redirectUrl=http://www.domain.com/www.hacker.net。
www.test.com/?redirectUrl=http://www.domain.com?www.hacker.net。
www.test.com/?redirectUrl=http://www.domain.com@www.hacker.net。
www.test.com/?redirectUrl=http://www.domain.com#www.hacker.net。
- 开发人员对于传入的 URL地址进行切割、拼接,导致攻击者可以利用其代码本身的逻辑进行绕过;
- 由于使用的开发语言的特性、服务器/容器特性、浏览器特性等对标准 URL 协议解析处理等差异性导致被绕过;
- 由于使用的开发语言的某些判断域名的函数库出现逻辑漏洞或者意外特性,导致被绕过。
(三)URL 跳转漏洞审计

通过搜索我们不难找到 RedirectController.java 文件中存在 sendRedirect 关键字,接着我们只需和 XSS 漏洞一样查看前后逻辑以及参数是否可控。这里可以清晰地看见程序是通过 GET 方法获得 url 参数,随后拼入 sendRedirect 方法进行跳转的,如图 3-2 所示


(四)修复
- 若跳转的 URL 事先是可以确定的,那么设置好白名单,并且采用全匹配的方式去检索关键字/域名;也可以先配置好相关参数,只需传对应 URL 的索引即可通过索引找到对应的具体 URL,然后再进行跳转。
- 若事先无法确定跳转的 URL,且并不是由用户通过参数传入的,那么可以首先生成跳转链接,然后进行签名,只有通过验证签名才能进行跳转。
- 若跳转的 URL 事先无法确定,并且是由用户通过参数传入的,则必须在跳转时对传入的 URL 进行详细校验,包括但不局限于:是否是白名单内的 URL,是否包含有相关特殊字符,是否处理好不规则协议、不规则地址的请求等方式。
小结
URL 跳转漏洞容易被安全人员忽视,认为其仅能够进行钓鱼攻击,但其实在各种复杂的实际场景中,URL 跳转漏洞也可以引起 XSS 等漏洞,因此绝不可以忽视其危害性。目前若发现此类型漏洞并汇报给国外厂商,汇报者可以获得几十到几百美元不等的报酬,可以看出厂商对于此类型漏洞的重视。对于安全审计人员来说,审计该类型漏洞时,不仅要重点关注上文中提到的关键参数和关键函数,还应对开发者编写的跳转限制规则进行 fuzzing 测试,判断是否有可用的特殊字符或者特殊编码来绕过限制