登录绕过漏洞:getContextPath() + getServletPath()和 getRequestURI 区别

609 阅读2分钟

在Java Web应用中,HttpServletRequest对象提供了多个方法来获取请求的路径信息。

HttpServletRequest中几个解析URL的函数

在Servlet处理URL请求的路径时,HTTPServletRequest有如下几个常用的函数:

  • request.getRequestURL():返回全路径;
  • request.getRequestURI():返回除去Host(域名或IP)部分的路径;
  • request.getContextPath():返回工程名部分,如果工程映射为/,则返回为空;
  • request.getServletPath():返回除去Host和工程名部分的路径;
  • request.getPathInfo():仅返回传递到Servlet的路径,如果没有传递额外的路径信息,则此返回Null;

当后台程序使用getRequestURI()或getRequestURL()函数来解析用户请求的URL时,若URL中包含了一些特殊符号,则可能会造成访问限制绕过的安全风险。 

举例:

mport org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping("/some") // 基础路径
public class PathInfoController {

    @GetMapping("/path") // 请求路径
    public String getPathInfo(HttpServletRequest request) {
        String contextPath = request.getContextPath();
        String servletPath = request.getServletPath();
        String pathInfo = request.getPathInfo();
        String requestURI = request.getRequestURI();

        return "Context Path: " + contextPath + "\n" +
               "Servlet Path: " + servletPath + "\n" +
               "Path Info: " + pathInfo + "\n" +
               "Request URI: " + requestURI;
    }
}

假设你访问的URL为 http://localhost:8080/some/path,那么输出将会是:

Context Path: /
Servlet Path: /some/path
Path Info: null
Request URI: /some/path

攻击利用:

新建一个filter包,其中新建一个testFilter类,实现Filter接口类:
public class testFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;

        String url = httpServletRequest.getRequestURI();

        if (url.startsWith("/some/path")) {            
            httpServletResponse.getWriter().write("No Permission.");
            return;
        }

        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

可以绕过的场景:

http://localhost:8080/some/./path
http://localhost:8080/some/;mi1k7ea/path
http://localhost:8080/some/mi1k7ea/../path
http://localhost:8080/some/mi1k7ea/..;/path
http://localhost:8080//some/path

爆出的Apache Shiro的CVE中,就是使用getRequestURI()函数导致的,这里可以看到Shiro的补丁其实就是用getPathInfo()替换掉:github.com/apache/shir…

举例中filter绕过鉴权的漏洞修复可以用 httpRequest.getContextPath() + httpRequest.getServletPath()替换httpServletRequest.getRequestURI()