浅谈SpringWeb中获取当前请求路径的方式
字数 2984 2025-08-10 08:28:29
Spring Web 中获取当前请求路径的方式详解
0x00 前言
在实际业务中,为了防止越权操作,通常会根据对应的URL进行鉴权操作。Spring Security虽然提供了完善的鉴权/认证流程,但有时开发者会选择使用自定义的filter或interceptor来实现权限控制,这种方式更加灵活且适合小型项目或特殊需求。
0x01 常见的权限绕过案例
自定义权限控制通常通过获取当前URI/URL与权限控制表进行比对,若获取到的uri没有进行规范化处理,结合Spring Web URL匹配特性,可能存在绕过风险。
1.1 Spring Web URL匹配特性
1.1.1 SuffixPatternMatch(后缀匹配模式)
- 通过
PathMatchConfigurer.setUseSuffixPatternMatch(Boolean suffixPatternMatch)设置 - 设置为true时,路径
/xx和/xx.*等效 - Spring Boot默认false,5.3+版本默认值由true变为false
1.1.2 TrailingSlashMatch(结尾匹配模式)
- 通过
PathMatchConfigurer.setUseTrailingSlashMatch(Boolean trailingSlashMatch)设置 - 设置为true时,路径
/xx和/xx/等效 - Spring MVC默认开启
- PathPattern解析时会根据
matchOptionalTrailingSeparator处理(默认为true)
1.1.3 alwaysUseFullPath
- Spring Web < 5.3.x:路由匹配时会进行路径标准化(使用
getPathWithinServletMapping处理) - 5.3.x版本:使用
getPathWithinApplication处理,仅简单URL解码,不处理../跨目录请求
1.1.4 AntPathMatcher和PathPattern的区别
AntPathMatcher:根据alwaysUseFullPath值进行不同程度的路径净化处理PathPattern:仅移除URL路径中分号之后的内容和JSESSIONID参数,Controller匹配时会对URL编码解码
常见绕过方式
- 路径穿越符:
/login/../xx.do - URL编码:
/xx.%64%6f(do的url编码) - 分隔符:
/xx.do; - 结尾匹配:
/xx.do/
0x02 获取当前请求路径的方式
2.1 使用javax.servlet.http.HttpServletRequest
2.1.1 request.getRequestURI() & request.getRequestURL()
getRequestURI():返回包含路径和查询参数的URI字符串getRequestURL():返回包含完整URL的StringBuffer对象- 两者均未对path进行归一化处理:
- 不处理
../ - 获取不到
&连接的参数键值对,但能获取分隔符;及内容 - 不对URL解码
- 不处理
2.1.2 request.getServletPath() & request.getPathInfo()
getServletPath():返回Servlet路径(相对于上下文根的部分)getPathInfo():返回Servlet路径之后的额外路径信息- 通常配合使用:
request.getServletPath() + (request.getPathInfo() == null ? "" : request.getPathInfo()) - 会进行规范化处理:解码、处理分隔符和路径穿越符
2.2 SpringWeb中自带的方法
2.2.1 ServletRequestPathUtils
ServletRequestPathUtils.getCachedPath(request):- 从
UrlPathHelper.PATH_ATTRIBUTE或ServletRequestPathUtils.PATH_ATTRIBUTE获取 UrlPathHelper.PATH_ATTRIBUTE:受alwaysUseFullPath影响- false:路径标准化(解码、
//替换为/、处理跨目录) - true:仅简单URL解码,不处理
../
- false:路径标准化(解码、
ServletRequestPathUtils.PATH_ATTRIBUTE:不进行过多规范化处理
- 从
2.2.2 RequestContextHolder.getRequestAttributes
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getRequestURL().toString()- 等同于直接调用
request.getRequestURI()
2.2.3 ServletUriComponentsBuilder.fromCurrentRequest()
ServletUriComponentsBuilder.fromCurrentRequestUri()- 对
request.getRequestURI()的封装,返回内容未规范化
2.2.4 HandlerMapping属性
PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE:- 从
initLookupPath获取 PathPattern模式下仅移除分号后内容和JSESSIONID参数- 不进行URL解码(仅在PathPattern链式匹配时解码)
- 多层
///在@GetMapping("/**")时可能绕过
- 从
BEST_MATCHING_PATTERN_ATTRIBUTE:- 返回配置的Controller对应路径信息
- 避免归一化规范处理不足的问题
- 直接强关联匹配资源,适合权限控制
0x03 其他建议
-
使用Spring Security的
HttpFirewall接口拦截非法请求:StrictHttpFirewall(默认):拦截路径穿越符、多重/、分隔符等DefaultHttpFirewall
-
对接口访问进行标准化处理:
- 剔除
../、分隔符;后内容等 - 使用ESAPI的
canonicalize方法:ESAPI.encoder().canonicalize(URI) - 在
ESAPI.properties中禁用双重URI编码:Encoder.AllowMultipleEncoding=false
- 剔除
-
代码审计时注意不同获取方式的特点,判断是否存在绕过可能
最佳实践总结
- 对于权限控制,优先使用
BEST_MATCHING_PATTERN_ATTRIBUTE获取路径 - 如需获取完整路径,使用
request.getServletPath() + request.getPathInfo() - 实现自定义鉴权时,应对路径进行规范化处理
- 启用
StrictHttpFirewall拦截非法请求 - 高版本Spring(5.3+)默认使用
PathPattern,注意其与AntPathMatcher的区别