在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()