12 KiB
CVE-2026-41844 Spring Framework 开放重定向漏洞浅析
QIANXIN Team 来源:https://forum.butian.net/share/4951
0x00 CVE-2026-41844
Spring Framework:
- 7.0.0 - 7.0.7
- 6.2.0 - 6.2.18
- 6.1.0 - 6.1.27
- 5.3.0 - 5.3.48
以及不再支持维护的版本同样受到影响。
0x01 漏洞分析与复现
1.1 分析过程
以spring-webmvc 6.0.7为例。
当Spring MVC接收到请求时,Servlet容器会调用DispatcherServlet的service方法(方法的实现在其父类FrameworkServlet中定义):
经过一系列的处理后,会调用doDispatch方法处理:
在doDispatch方法中,经过一系列处理获取到url 和 Handler 映射关系后(HandlerAdapter),springMVC就可以根据请求的uri来找到对应的Controller和method,然后处理和响应请求。详细的分析可见https://forum.butian.net/share/2214
找到对应的HandlerAdapter后,会调用对应的Handler方法,也就是执行Controller里的业务逻辑了,执行完成之后会返回一个ModleAndView对象,然后渲染视图并进行返回,这里的逻辑是本次漏洞的分析的关键:
在获取到ModelAndView对象后,这里会调用applyDefaultViewName处理,这里是Spring 的默认视图解析逻辑:
查看具体的代码逻辑,首先检查 mv 是否为 null(如果代码添加了 @ResponseBody 注解,mv 就为 null),然后判断 mv 中是否包含视图,如果对应的Controller代码中未显式指定视图名时,则调用 getDefaultViewName 方法去获取默认的视图名,并将获取到的默认视图名赋值给 mv:
查看getDefaultViewName,看看具体获取默认视图名的逻辑:
这里会继续调用viewNameTranslator#getViewName方法对请求进行处理。
viewNameTranslator 其实是 RequestToViewNameTranslator:
本质上,在 SpringMVC 中,RequestToViewNameTranslator 接口只有一个默认的实现类DefaultRequestToViewNameTranslator,WebFlux 则是ViewResolutionResultHandler 。
在DefaultRequestToViewNameTranslator#getViewName方法中,会从请求路径中直接提取字符串作为视图名:
ServletRequestPathUtils#getCachedPathValue方法是统一获取请求路径的方法。具体的解析可见https://forum.butian.net/share/2606。
提取完请求路径后,会通过 transformPath 方法对路径进行处理,再分别加上前后缀后返回,默认的前后缀都是空字符串(如有需要,也可以进行配置)。
transformPath 方法则主要功能如下:
- 去掉路径开始的
/ - 去掉路径结尾的
/ - 如果请求路径有扩展名,则去掉扩展名,例如请求路径是
/1.txt,经过这一步处理后,就变成了/1
- 如果 separator 与 SLASH 不同,则替换原来的分隔符(一般情况下,默认是相同的)。
这里以如下Controller为例:
@GetMapping("/**")
public void catchAll() {
}
当正常请求/demo时,可以看到,因为没有显示指定视图,所以ModelAndView对象里的内容均为null:
经过applyDefaultViewName方法处理后,取得对应的视图名,也就是默认的请求路径demo:
这里也就得到了漏洞的第一个成因:当 Spring MVC 或 Spring WebFlux 应用未显式指定视图名时,视图名会默认从请求路径提取。
处理完上述的一系列逻辑后,会调用processDispatchResult()进行异常处理、请求状态及触发请求完成事件,视图的渲染工作则交给了render()方法:
render()渲染过程中,如果ModelAndView中的viewName不为空,则调用resolveViewName从视图解析器获取对应的视图对象;否则使用ModelAndView#getview方法获取视图对象。
这里会进一步调用getCandidateViews方法进行处理,然后遍历所有的视图解析器,进行视图的创建与解析:
而UrlBasedViewResolver会识别视图名中的特殊前缀,例如redirect: 会被解析为重定向,返回 302 响应跳转到后续指定的地址:
至此,CVE-2026-41844的完整链路大致梳理清楚了。下面是具体的漏洞复现过程。
1.2 漏洞复现
以SpringMVC为例:
相关环境直接使用https://github.com/andbin/spring-boot3-thymeleaf-basic-demo 进行验证。
根据前面的分析,可以定义一个Controller如下:
@Controller
public class MyController {
@GetMapping("/**")
public void catchAll() {
}
}
启动对应的application后,只需访问http://ip:port/redirect:https://www.attack.com.any,通过302跳转后即可重定向到https://www.attack.com
注意,根据前面的分析,在通过请求获取默认视图时,如果请求路径有扩展名,则去掉扩展名,这个拓展名会通过结尾最后一个.来区分。也就是说类似www.attack.com会被处理成www.attack,所以在最后构造poc时,要在实际跳转的域名后,增加类似.any的后缀,避免截断后无法正常跳转。
下面是具体的效果:
forward的转发同理,先定义一个转发的目标:
@GetMapping("/internal/secret")
@ResponseBody public String internalEndpoint() {
return "[敏感信息] 内部系统配置接口,仅内网可访问";
}
只需请求http://ip:port/forward:/internal/secret即可成功转发:
Spring WebFlux同理,这里就不再赘述了。
另外,WebFlux 原生不支持 forward: 内部转发,因此仅受 redirect: 开放重定向影响。
1.3 {*spring}模式
在官方的漏洞通告中,仅仅提到了/**的场景,实际上Spring5及之后的PathPattern解析模式,还支持类似{*spring}的写法,与/**大同小异,那么是否也会存在风险呢?
查看官方文档:
Representation of a parsed path pattern. Includes a chain of path elements for fast matching and accumulates computed state for quick comparison of patterns.
PathPattern matches URL paths using the following rules:
?matches one character*matches zero or more characters within a path segment**matches zero or more path segments until the end of the path{spring}matches a path segment and captures it as a variable named "spring"{spring:[a-z]+}matches the regexp[a-z]+as a path variable named "spring"{*spring}matches zero or more path segments until the end of the path and captures it as a variable named "spring"
Note: In contrast to [AntPathMatcher](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html), ** is supported only at the end of a pattern. For example, /pages/{} is valid but /pages/{}/details is not. The same applies also to the capturing variant {*spring}. The aim is to eliminate ambiguity when comparing patterns for specificity.
根据官方文档的描述,其实**跟AntPathMatcher匹配规则区别不大,PathPattern在保持其匹配规则的基础上,新增了{*spring}的语法支持。
{*spring}表示匹配余下的path路径部分并将其赋值给名为spring的变量(变量名可以根据实际情况随意命名,与@PathVariable名称对应即可)。同时,{*spring}是可以匹配剩余所有path的,类似/**,只是功能更强,可以获取到这部分动态匹配到的内容。
@GetMapping("/{*path}")
public void catchAll() {
}
可以发现,同样成功利用,这里与/**的配置区别只是解析模式的不同,不影响具体的漏洞触发:
0x02 利用条件
综上所述,相关漏洞的利用条件可以总结如下:
- 使用 Spring MVC 或 Spring WebFlux 框架
- 配置了类似
/**通配符路径与{*path}映射(如全局视图路由) - 对应路径的处理器未显式指定视图名称,依赖 Spring 自动从请求路径推导
- 使用了继承自
UrlBasedViewResolver的视图解析器(Thymeleaf等主流视图技术默认均满足)
0x03 修复方案
通过请求获取完视图名后,新增对 redirect:、forward: 两个危险前缀的开头匹配校验。当匹配到危险前缀时直接抛出非法参数异常,由 Spring MVC 异常处理器转为 400 Bad Request 响应:

























