Spring的getRequestURI與getRequestURL方法導致安全風險 1. 測試代碼 2. 繞過方式 3. 預防措施 推薦閱讀

我們有時候會在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設計缺陷導致的權限繞過

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章