浅谈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编码解码

常见绕过方式

  1. 路径穿越符:/login/../xx.do
  2. URL编码:/xx.%64%6f(do的url编码)
  3. 分隔符:/xx.do;
  4. 结尾匹配:/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_ATTRIBUTEServletRequestPathUtils.PATH_ATTRIBUTE获取
    • UrlPathHelper.PATH_ATTRIBUTE:受alwaysUseFullPath影响
      • false:路径标准化(解码、//替换为/、处理跨目录)
      • true:仅简单URL解码,不处理../
    • 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 其他建议

  1. 使用Spring Security的HttpFirewall接口拦截非法请求:

    • StrictHttpFirewall(默认):拦截路径穿越符、多重/、分隔符等
    • DefaultHttpFirewall
  2. 对接口访问进行标准化处理:

    • 剔除../、分隔符;后内容等
    • 使用ESAPI的canonicalize方法:
      ESAPI.encoder().canonicalize(URI)
      
    • ESAPI.properties中禁用双重URI编码:
      Encoder.AllowMultipleEncoding=false
      
  3. 代码审计时注意不同获取方式的特点,判断是否存在绕过可能

最佳实践总结

  1. 对于权限控制,优先使用BEST_MATCHING_PATTERN_ATTRIBUTE获取路径
  2. 如需获取完整路径,使用request.getServletPath() + request.getPathInfo()
  3. 实现自定义鉴权时,应对路径进行规范化处理
  4. 启用StrictHttpFirewall拦截非法请求
  5. 高版本Spring(5.3+)默认使用PathPattern,注意其与AntPathMatcher的区别
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解码,不处理 ../ 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.properties 中禁用双重URI编码: 代码审计时注意不同获取方式的特点,判断是否存在绕过可能 最佳实践总结 对于权限控制,优先使用 BEST_MATCHING_PATTERN_ATTRIBUTE 获取路径 如需获取完整路径,使用 request.getServletPath() + request.getPathInfo() 实现自定义鉴权时,应对路径进行规范化处理 启用 StrictHttpFirewall 拦截非法请求 高版本Spring(5.3+)默认使用 PathPattern ,注意其与 AntPathMatcher 的区别