java中url任意跳转漏洞的解决
作者:乐队1
1 漏洞介绍
URLRedirect url重定向漏洞也称url任意跳转漏洞,网站信任了用户的输入导致恶意攻击,url重定向主要用来钓鱼,比如url跳转中最常见的跳转在登陆口,支付口,也就是一旦登陆将会跳转任意自己构造的网站,如果设置成自己的url则会造成钓鱼。url跳转常见的地方包括:
- 登陆跳转我认为是最常见的跳转类型,认证完后会跳转,所以在登陆的时候建议多观察url参数
- 用户分享、收藏内容过后,会跳转
- 跨站点认证、授权后,会跳转
- 站内点击其它网址链接时,会跳转
- 在一些用户交互页面也会出现跳转,如请填写对客服评价,评价成功跳转主页,填写问卷,等等业务,注意观察url。
- 业务完成后跳转这可以归结为一类跳转,比如修改密码,修改完成后跳转登陆页面,绑定银行卡,绑定成功后返回银行卡充值等页面,或者说给定一个链接办理VIP,但是你需要认证身份才能访问这个业务,这个时候通常会给定一个链接,认证之后跳转到刚刚要办理VIP的页面。
2 审计方法
结合业务场景,通过关键字在web层(Controller、Servlet类文件)中搜索一下关键字,确定漏洞的依据就是看是否直接转发、直接跳转、直接重定向的目的URL是源于前端且没有处理。常见关键字如下:
3 审计案例
3.1 案例1-302 redirect
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/urlRedirection/setHeader" method="get" enctype="multipart/form-data"> <input type="text" name="url" > <input type="submit"> </form> </body> </html>
@Controller @RequestMapping("/urlRedirection") public class URLRedirectionController { //去重定向前端页面 @GetMapping("/toRedirectPage") public String toRedirectPage(){ System.out.println("重定向漏洞页面"); return "Demo13"; } //302跳转 @GetMapping("/urlRedirection") public void urlRedirection(HttpServletRequest request, HttpServletResponse response) throws IOException { String url = request.getParameter("url"); response.sendRedirect(url); } }
通过上述代码,能够得出,urlRedirection方法接收了源于form表单的参数后直接通过
response.sendRedirect(url)重定向,也就是说直接访问了来自前端url参数的url。
当提交之后会直接跳转到百度页面,因此具有一定的风险性
需要注意的是外部网址必须加http.www,只写域名仍然在改服务器上
3.2 案例2-301 redirect
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/urlRedirection/setHeader" method="get" enctype="multipart/form-data"> <input type="text" name="url" > <input type="submit"> </form> </body> </html>
//去重定向前端页面 @GetMapping("/toRedirectPage") public String toRedirectPage(){ System.out.println("重定向漏洞页面"); return "Demo13"; } @RequestMapping("/setHeader") @ResponseBody public static void setHeader(HttpServletRequest request, HttpServletResponse response) { String url = request.getParameter("url"); response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301 redirect response.setHeader("Location", url); }
同案例1的失效效果一样,只不过是后端发生跳转的类型不一致而已。
3.3 案例3-urlRedirection重定向
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/urlRedirection/setHeader" method="get" enctype="multipart/form-data"> <input type="text" name="url" > <input type="submit"> </form> </body> </html>
@GetMapping("/redirect") public String redirect(@RequestParam("url") String url) { return "redirect:" + url; }
同案例1、2的效果一样,只不过是后端发生跳转的类型不一致而已。初次外获取参数的形式不一样,通过注解获取的。
四、修复意见(二选一)
1、将重定向改成转发
转发(前往),服务器内部的重定向,在Servlet中通过RequestDispatcher转发给另一个程序处理请
求,请求的数据依然在。所以forward相当于客户端向服务器发送一次请求,服务器处理两次,请求数
据不会消失且URL地址只变化一次。因为转发只能在服务器内部进行(内部跳转),不会跳转到外
部。参考代码如下:
<%@ page contentType="text/html; charset=UTF-8" %> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/urlRedirection/forward" method="get" enctype="multipart/form-data"> <input type="text" name="url" > <input type="submit"> </form> </body> </html>
@RequestMapping("/forward") @ResponseBody 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(); } }
此时在提交百度一下,你就知道,发现无法跳转成功
2、白名单与黑名单相结合的限制
就是将需要重定向的目的URL整理成白名单,在进行重定向前匹配,如果不在白名单中禁止重定向。
相关白名单校验参考代码如下:
/** * 同时支持一级域名和多级域名,相关配置在resources目录下url_safe_domain.xml文件。 * 优先判断黑名单,如果满足黑名单return null。 * * @param url the url need to check * @return Safe url returns original url; Illegal url returns null; */ public String checkURL(String url) throws IOException { if (null == url){ return null; } try { URL url1 = new URL(url); String host = url1.getHost(); // 必须http/https if (!url1.getProtocol().equals("https") && !url1.getProtocol().equals("http")) { return null; } // 如果满足黑名单返回null if (blackDomains.contains(host)){ return null; } for(String blockDomain: blackDomains) { if(host.endsWith("." + blockDomain)) { return null; } } // 支持多级域名 if (safeDomains.contains(host)){ return url; } // 支持一级域名 for(String safedomain: safeDomains) { if(host.endsWith("." + safedomain)) { return url; } } return null; } catch (NullPointerException | MalformedURLException e) { e.printStackTrace(); return null; } } }
例如黑名单和白名单的配置如下
safeDomains=127.0.0.1,127.0.0.2 blackDomains=baidu.com,qq.com
当输入baidu.com时,将无法跳转。
当将baidu.com添加到白名单,同时从黑名单中剔除出去,将成功跳转
到此这篇关于java中url任意跳转漏洞的解决的文章就介绍到这了,更多相关java url任意跳转漏洞内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!