任意URL跳转漏洞服务器不对传入的跳转url变量进行检查和控制,导致恶意构造任意恶意地址,诱导用户跳转到恶意网站。因为是从可信站点重定向过来的,用户会信任它,所以重定向漏洞一般用于钓鱼攻击,通过转到恶意网站欺骗用户输入用户名和密码窃取用户信息,或者欺骗用户进入金钱交易。修复此漏洞最有效的方法之一是检查传入的重定向url的参数值,以确定它是否是预期的域名。java中可以使用以下方法:Stringurl=request.getParameter("returnUrl");Stringhost="";try{host=newURL(url).getHost();}catch(MalformedURLExceptione){e.printStackTrace();}ifhost.endsWith(".bbb.com"){//跳转}else{//不跳转,报错}上面代码主要检查客户端发送的returnUrl参数值,使用java.net.URLpackage方法中的getHost()方法获取url将重定向到的host,判断host是否为目标域。上面的代码限制了必须重定向到xxx.bbb.com的域名,从而杜绝了重定向到不可信域名的可能性。然而,getHost()方法真的靠谱吗??getHost()方法的一个陷阱可以通过一个反斜杠绕过,即returnUrl=http://www.aaa.com\www.bbb.com会被编码以为是即将跳转到bbb.com,但在浏览器中将反斜杠修正为正斜杠,跳转到www.aaa.com/www.bbb.com,最后跳转到www.aaa.com服务器。使用如下代码测试:publicclassMain{publicstaticvoidmain(String[]args){Stringurl="https://www.aaa.com\\www.bbb.com?x=123";Stringhost="";try{host=newURL(url).getHost();}catch(MalformedURLExceptione){e.printStackTrace();}System.out.println("host---"+host);System.out.println("url---"+url);}}getHost()后url参数的域名是www.aaa.com还是www.bbb.com?打印结果如下:endsWith(“.bbb.com”)方法会判断结果为真,从而跳转成功,但浏览器实际跳转到www.aaa.com网站。getHost()方法的第二个坑getHost()方法的结果对于hashtag#的处理结果在不同的JDK版本中是不同的,通常hashtag作为页面锚点,对于https://www.aaa.com#wwwurl.bbb.com?x=123,在高版本的JDK中,结果为www.aaa.com,在低版本中为www.aaa.com#www.bbb.com,所以低版本可以绕过endsWith(“.bbb.com”)方法,跳转成功。这里所说的高版本指的是java版本1.8.0_181或者java版本1.7.0_161中的181和161,不管JDK7还是8。可能java在某个时候修复了JDK6/7/8中的url库。测试的时候发现1.6.0_45、1.7.0_71、1.8.0_25都可以通过#绕过,也就是不同的JDK版本有问题。通过对比rt.jar---java---net--URLStreamHandler.java代码(左边是低版本,右边是高版本)找到问题所在,如下图所示,代码中的start是url中冒号的位置,limit是url中井号的位置:从代码中可以发现斜线/或问号?在较低版本中不考虑完整的url。前面会有井号#。如果有斜线/或问号?在url中,把host以斜线或者问号结束,即使中间包含井号也不处理;但在高版本中,判断了井号的位置,排除了绕过使用井号的可能。但是网上生成环境的JDK版本是不敢乱升级的,只能从代码上提前预防。下图是使用不同版本JDK的测试结果:同一段代码在不同的JDK版本中打印出不同的host值,低版本包含井号及其后的部分。结合以上两个陷阱,如果想使用getHost()修复任意URL跳转漏洞,需要考虑反斜杠和井号绕过,可以使用如下代码:Stringurl=request.getParameter("returnUrl");Stringhost="";try{urrlurl=url.replaceAll("[\\\\#],"/");//替换反斜杠和井号host=newURL(url).getHost();}catch(MalformedURLExceptione){e.printStackTrace();}ifhost.endsWith(".bbb.com"){//跳转}else{//不跳转,报错}附上真实例子,本站可以使用井号加斜杠或问号绕过域名检测,即URL编码后将target设置为https://www.baidu.com#www.bbb.com?x=123,站点可302跳转到百度。
