java-sec-code中重定向

重定向
状态码3xx
存在问题的代码段

@GetMapping("/redirect")
public String redirect(@RequestParam("url") String url) {
    return "redirect:" + url;
}

用户访问/redirect路径时,redirect方法会获取web请求中的url参数内容,并使用springboot中的redirect控制器,重定向到用户想要前往的界面

复现

http://127.0.0.1:8080/urlRedirect/redirect?url=http://www.baidu.com

网站会直接打开百度界面,burpsuite中则为302重定向状态码
在这里插入图片描述

@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);
}

访问/setHeader路由时,服务端会接受url参数内容,设置网站响应状态码为301,并将网站相应的Location头(用于指向重定向的目标url)设置为url内容,并且没有任何过滤

复现

http://localhost:8080/urlRedirect/setHeader?url=http://www.baidu.com

网站显示为baidu界面,burpsuite显示的内容为301状态码
在这里插入图片描述

@RequestMapping("/sendRedirect")
@ResponseBody
public static void sendRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String url = request.getParameter("url");
    response.sendRedirect(url);
}

代码段采用Java Servlet API中的redirect方法,用于将HTTP请求重定向到指定的URL(302)。

复现

http://127.0.0.11:8080/urlRedirect/sendRedirect?url=http://www.baidu.com

网站显示为百度界面,burpsuite显示的内容为302状态码
在这里插入图片描述
安全的代码写法

@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();
    }
}

从用户请求中获取url参数内容,设置RequestDispatcher对象,将用户的请求发送到url地址中,调用forward方法将请求和响应对象转发到url中,由于RequestDispatcher是用来在服务器端进行请求的内部处理和转发,所以只能在同源网站内进行跳转,无法跳转到外部网站
复现

http://127.0.0.1:8080/urlRedirect/forward?url=/urlRedirect/redirect

burpsuite中请求包,首先有一个重定向的数据包,然后请求重定向后的路由
在这里插入图片描述
在这里插入图片描述
如果是外部网站,状态码为200,路由,界面显示均无变化,并且idea中会显示请求转发到错误页面时出现了问题。

在这里插入图片描述

@RequestMapping("/sendRedirect/sec")
@ResponseBody
public void sendRedirect_seccode(HttpServletRequest request, HttpServletResponse response)
        throws IOException {
    String url = request.getParameter("url");
    if (SecurityUtil.checkURL(url) == null) {
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.getWriter().write("url forbidden");
        return;
    }
    response.sendRedirect(url);
}

}

接受url参数,使用check方法过滤,白名单黑名单位置在url/url_safe_domain.xml

<safedomains>//白名单
    <!-- 支持一级域名或多级域名 -->
    <domain>joychou.com</domain>
    <domain>joychou.org</domain>
    <domain>test.joychou.org</domain>
    <domain>localhost</domain>
</safedomains>

<!-- 支持一级域名或多级域名 -->
<blockdomains>//黑名单名单
    <domain>baidu.com</domain>
    <domain>evil.joychou.org</domain>
</blockdomains>

check方法,假设传入的参数为http://test.joychou.org

public static String checkURL(String url) {

    if (null == url){ //检测是否为空
        return null;
    }
       //读取文件中的黑白名单
    ArrayList<String> safeDomains = WebConfig.getSafeDomains();//白名单
    ArrayList<String> blockDomains = WebConfig.getBlockDomains();//黑名单

    try {
        String host = gethost(url);//test.joychou.org 获取host值

        // 检测是否为http/https
        if (!isHttp(url)) {
            return null;
        }

        // 如果满足黑名单返回null   将host与黑名单中进行比对,有则null
        if (blockDomains.contains(host)){
            return null;
        }
      //检测host属性值是否有黑名单后缀,用于去除黑名单域名与其子域名
        for(String blockDomain: blockDomains) {
            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 e) {
        logger.error(e.toString());
        return null;
    }
}

当用户传入的为白名单的网址则进行跳转,否则输出url forbidden

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值