CVE-2026-47887:Spring Framework UrlFilenameViewController 重定向漏洞浅析
漏洞分析
spring-webmvc 模块提供 MVC 控制器与视图解析能力,UrlFilenameViewController 会把请求 URL 路径转换为视图名。受影响版本中,当应用将 UrlFilenameViewController 以路径末尾匹配方式映射且未配置 prefix 时,攻击者可提交以 redirect: 开头的路径,从而把用户浏览器重定向到任意外部地址。
0x00 CVE-2026-47887 ===================  **影响版本:** Spring Framework: - 7.0.0 - 7.0.8 - 6.2.0 - 6.2.19 - 6.1.0 - 6.1.28 - 6.0.0 - 6.0.30 - 5.3.0 - 5.3.49 - 5.2.25 and earlier 0x01 漏洞分析与复现 ============ 1.1 UrlFilenameViewController ----------------------------- `UrlFilenameViewController` 是 Spring Framework中的一个简单控制器。它不需要写任何业务代码,就能直接把请求 URL 里的文件名变成视图名字。比如访问 `/index.html`,它就会返回名为 `index` 的视图。这样新增加一个view就多一个可访问页面, 还不用为每个静态页面单独写控制器类,使用起来十分方便。  主要核心功能如下: - **转换路径**:去掉斜杠和后缀,把 URL 变成视图名。 - **支持前缀后缀**:可以加前缀或后缀来拼出最终的视图名字。 - **无需业务逻辑**:适合没有后台代码、只是单纯要做页面跳转的静态请求 可能一看到Controller,很多人会误认为这是一个实际业务的调用,但是实际上UrlFilenameViewController的调用方是Spring MVC 的入口**`DispatcherServlet`\*\***。\*\* 使用的话一般有两种方式: - **XML配置**: ```XML <!-- 路由表:/**/*.html 的请求都交给 urlFilenameController --> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props><prop key="/**/*.html">urlFilenameController</prop></props> </property> </bean> <!-- 控制器:把 URL 文件名翻译成视图名(/index.html → "index") --> <bean id="urlFilenameController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/> <!-- 视图解析器:视图名拼上前缀/后缀,落到实际 JSP("index" → /WEB-INF/jsp/index.jsp) --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> ``` - **在WebConfig通过Bean注入** ```TypeScript @Configuration public class WebConfig { @Bean public UrlFilenameViewController urlFilenameViewController() { // 不设置 prefix 的话视图名原样来自 URL 路径 return new UrlFilenameViewController(); } @Bean public SimpleUrlHandlerMapping urlFilenameHandlerMapping(UrlFilenameViewController controller) { SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); Properties mappings = new Properties(); mappings.put("/**", controller); mapping.setMappings(mappings); // 先于 Boot 默认的静态资源 HandlerMapping(order = MAX-1)命中 mapping.setOrder(Ordered.LOWEST_PRECEDENCE - 2); return mapping; } } ``` 以WebConfig的配置为例,当前项目结构如下,可以看到没有定义任何额外的Controller:  直接访问即可成功访问到对应的视图资源:  1.2 漏洞复现与分析过程 ------------- 以**spring-webmvc 6.2.19**为例,查看具体的实现逻辑。 首先从DispatcherServlet#doDispatch方法开始分析,每个请求经过时,会先匹配 HandlerMapping 路由表, 再挑一个适配器去调用Controller:  以1.1的配置为例,可以看到当请求index.html时确实会调用UrlFilenameViewController进行解析:  继续往下跟进,会通过SimpleControllerHandlerAdapter#handle方法进行处理:  然后在`AbstractUrlViewController.handleRequestInternal`(`UrlFilenameViewController` 的父类)处理:   继续跟进handleRequestInternal方法,这里会得到请求的视图名,然后包装成`ModelAndView` 返回:  得到ModelView对象后,会在DispatcherServlet#render方法拿视图名去进行ViewResolver 解析,然后渲染:  熟悉的师傅应该知道,如果resolveViewName可以引入类似redirect:开头的话,便有可能会导致任意URL重定向的风险:  所以着重分析下前面handleRequestInternal中解析视图名的逻辑,这里实际调用了UrlFilenameViewController#getViewNameForRequest方法进行处理:  在获取请求的uri后,主要通过extractViewNameFromUrlPath处理,然后得到对应的视图名:  extractViewNameFromUrlPath实现如下,逻辑比较简单,**主要是去掉前导的`/`,按最后一个`.`截断**。 例如`/index.html`最终会得到`index`:  最后通过postProcessViewName方法结合prefix跟suffix配置,返回最终的视图名:  可以看到整个过程中并没有对redirect:开头的路径请求进行限制,所以理论上是会存在任意URL重定向风险的。 根据前面的分析,poc也比较简单,首先是引入redirect:保证进入302跳转逻辑,然后因为extractViewNameFromUrlPath方法会截断最后一个`.`后的内容,为了保证正常的域名跳转,所以要多一个`.x`的逻辑:  从具体的数据包可以看到,解析后的Location的`https://`少了一个`/`,但是并不会影响正常跳转,浏览器对这类 special scheme 宽容解析,缺斜杠会自动补上。 另外少了一个`/`其实是PathPattern在路径匹配时,通过extractPathWithinPattern() 对多个`/`进行归一化处理导致的,但是实际上并不会影响漏洞的利用。 这里也解释下为什么在配置时需要配置: ```Java mapping.setOrder(Ordered.LOWEST_PRECEDENCE - 2); ``` 主要是为了让请求先于 Spring Boot 默认的静态资源 HandlerMapping(order = MAX-1)命中,如果去掉对应的逻辑的话,可以看到并不会交给UrlFilenameViewController进行解析:  当然了如果是MVC的项目通过XML进行配置,由于不像Springboot自动配置静态资源映射,理论上是可以直接利用的,这里只是为了复现方便。 1.3 利用条件 -------- - 应用使用 `UrlFilenameViewController` - 以 **end-of-path** 的方式映射(公告原话 "mapped with an end-of-path",指映射模式只约束路径结尾、尾段内容任意,如 `/**/*.html`、`/**` 等 - **未配置 prefix**,只要设置了 prefix(如 `views/`),视图名就变成 `views/redirect:...`,不再以 `redirect:` 开头,无法利用 0x02 修复方式 ========= 修复commit为https://github.com/spring-projects/spring-framework/commit/9312e25e2459aef305b5b1e9986d50f25a0afc08 ,方式也比较简单,通过在`UrlFilenameViewController` 新增 `checkViewName`,在返回视图名前拒绝特权前缀,保证**视图名不得以** **`redirect:`** **或** **`forward:`** **开头**,命中则返回 400:  另外,如果无法升级的话,可以考虑通过下面的方式进行缓解: 1. 为 `UrlFilenameViewController` 配置**非空 prefix** (如 `views/`,此时可以views/index进行访问),视图名便不可能再以 `redirect:`/`forward:` 开头。 2. 放弃 `UrlFilenameViewController`,改用显式的 `ViewControllerRegistry`(`registry.addViewController("/index").setViewName("index")`), 视图名不再从请求方输入推导。
发表于 2026-10-08 10:01:18
阅读 ( 7784 )
分类:
漏洞分析
1 推荐
收藏
0 条评论
tkswifty
81 篇文章
×
温馨提示
您当前没有「奇安信攻防社区」的账号,注册后可获取更多的使用权限。
×
温馨提示
您当前没有「奇安信攻防社区」的账号,注册后可获取更多的使用权限。
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!