美文网首页框架学习使用收藏spring
Spring的getRequestURI与getRequestU

Spring的getRequestURI与getRequestU

作者: 小胖学编程 | 来源:发表于2021-12-08 21:16 被阅读0次

    我们有时候会在Filter中对某些URL进行权限校验。若使用getRequestURI与getRequestURL方法获取URL,可能会导致权限绕过的风险。

    漏洞原理:请求URL中可以填充一些特殊字符,来跳过权限校验。

    1. 测试代码

    权限验证器代码:

    @Slf4j
    @Service
    public class URIRiskInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            //校验数据
            String requestURI = request.getRequestURI();
            String requestURL = request.getRequestURL().toString();
            String servletPath = request.getServletPath();
            log.info("输出数据requestURI:{}\n,requestURL:{}\n,servletPath:{}\n", requestURI, requestURL, servletPath);
            return true;
        }
    }
    

    Controller层代码:

    @Slf4j
    @RestController
    public class FirstController {
    
        @RequestMapping(value = "/test")
        public String test(@RequestParam("id") Long id, @RequestParam("name") String name) {
            log.info("test,请求进来了");
            return id + "-" + name + " is success";
        }
    }
    

    2. 绕过方式

    2.1 非标准化绕过

    例如/system/login开头的接口是白名单,不需要进行访问控制(登陆页面所有人都可以访问),其他接⼝都需要进⾏登陆检查,防止未授权访问:

    @Slf4j
    @Service
    public class URIRiskInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            //校验数据
            String requestURI = request.getRequestURI();
            String requestURL = request.getRequestURL().toString();
            String servletPath = request.getServletPath();
            log.info("输出数据requestURI:{}\n,requestURL:{}\n,servletPath:{}\n", requestURI, requestURL, servletPath);
            //放行登录请求
            if (requestURI.startsWith("/system/login")) {
                log.info("yes,跳过校验{}", requestURI);
            } else {
                log.info("no,进行校验{}", requestURI);
            }
            return true;
        }
    }
    

    执行结果:

    2021-12-07 16:13:23.114  INFO 11917 --- [nio-8080-exec-1] c.tellme.Interceptor.URIRiskInterceptor  : 输出数据requestURI:/system/login/../../test
    ,requestURL:http://localhost:8080/system/login/../../test
    ,servletPath:/test
    
    2021-12-07 16:13:23.115  INFO 11917 --- [nio-8080-exec-1] c.tellme.Interceptor.URIRiskInterceptor  : yes,跳过校验/system/login/../../test
    2021-12-07 16:13:23.127  INFO 11917 --- [nio-8080-exec-1] com.tellme.controller.FirstController    : test,请求进来了
    

    可以看到:当访问http://localhost:8080/system/login/../../test是可以访问到Controller方法的,且跳过了验证。

    2.2 URL截断绕过

    针对的是String.endsWith()的权限校验。

    @Slf4j
    @Service
    public class URIRiskInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            //校验数据
            String requestURI = request.getRequestURI();
            String requestURL = request.getRequestURL().toString();
            String servletPath = request.getServletPath();
            log.info("输出数据requestURI:{}\n,requestURL:{}\n,servletPath:{}\n", requestURI, requestURL, servletPath);
            //若结尾为.do或者.action的请求进行校验,但是SpringMVC很少有这种后缀的。
            if (requestURI.endsWith("test")) {
                log.info("no,进行校验{}", requestURI);
            } else {
                log.info("yes,跳过校验{}", requestURI);
            }
            return true;
        }
    }
    

    测试结果:

    2021-12-07 17:03:03.299  INFO 15815 --- [nio-8080-exec-1] c.tellme.Interceptor.URIRiskInterceptor  : 输出数据requestURI:/test;123
    ,requestURL:http://localhost:8080/test;123
    ,servletPath:/test
    
    2021-12-07 17:03:03.299  INFO 15815 --- [nio-8080-exec-1] c.tellme.Interceptor.URIRiskInterceptor  : yes,跳过校验/test;123
    2021-12-07 17:03:03.314  INFO 15815 --- [nio-8080-exec-1] com.tellme.controller.FirstController    : test,请求进来了
    

    可以看到:当访问http://localhost:8080/test;123是可以访问到Controller方法的,且跳过了验证。

    3. 预防措施

    • 未设置context-path的项目使用getServletPath来代替getRequestURI;
    • 在设置context-path的项目确定哪些api需要校验时,使用去掉context-path的路径;

    推荐阅读

    Tomcat URL解析差异性导致的安全问题

    filter设计缺陷导致的权限绕过

    相关文章

      网友评论

        本文标题:Spring的getRequestURI与getRequestU

        本文链接:https://www.haomeiwen.com/subject/wfqaxrtx.html