Spring 框架远程代码执行漏洞,预警公告

工程 | Rossen Stoyanchev | 2022 年 3 月 31 日 | ...

更新

  • [04-13] 发布了关于“数据绑定规则漏洞 CVE-2022-22968”的后续博客文章,与 建议的解决方法 中的“disallowedFields”相关
  • [04-08] Snyk 公告 了针对 Glassfish 和 Payara 的额外攻击向量。另请参阅相关的 Payara 和即将发布的 公告
  • [04-04] 更新了 我是否受到影响,并改进了部署要求的描述
  • [04-01] 更新了 我是否受到影响,并添加了其他说明
  • [04-01] 更新了 建议的解决方法 部分,以涵盖 Apache Tomcat 升级和 Java 8 降级
  • [04-01] 发布了后续博客文章“缓解方案”,宣布 Apache Tomcat 发布了版本 10.0.209.0.628.5.78,这些版本从 Tomcat 端关闭了攻击向量
  • [03-31] Spring Boot 2.6.6 可用
  • [03-31] Spring Boot 2.5.12 可用
  • [03-31] 发布了 CVE-2022-22965
  • [03-31] 添加了“误解”部分
  • [03-31] 添加了“我是否受到影响”部分
  • [03-31] 修复了添加 disallowedFields 的解决方法中的一个小问题
  • [03-31] Spring Framework 5.3.185.2.20 可用

目录

概述

我想宣布 Spring Framework 中存在一个远程代码执行漏洞,该漏洞在 CVE 发布之前就被泄露了。AntGroup FG 的 codeplutos 和 meizjm3i 于周二晚上接近格林威治标准时间午夜首次向 VMware 报告了此问题。周三,我们进行了调查、分析、确定修复方案、测试,同时目标是在周四发布紧急版本。与此同时,同样在周三,详细信息在网上被完全泄露,这就是我们在此发布版本和 CVE 报告之前提供此更新的原因。

漏洞

该漏洞影响在 JDK 9+ 上运行的 Spring MVC 和 Spring WebFlux 应用程序。特定的漏洞利用需要将应用程序打包并作为传统的 WAR 部署到 Servlet 容器上。如果应用程序作为 Spring Boot 可执行 jar 部署(即默认方式),则不会受到漏洞利用的影响。但是,漏洞的本质更普遍,可能存在其他利用方式。

我是否受到影响?

以下是报告中特定场景的要求

  • 在 JDK 9 或更高版本上运行
  • 作为 传统 WAR 打包并部署到独立的 Servlet 容器上。使用 嵌入式 Servlet 容器反应式 Web 服务器 的典型 Spring Boot 部署不受影响。
  • spring-webmvcspring-webflux 依赖项。
  • Spring Framework 版本 5.3.0 到 5.3.17、5.2.0 到 5.2.19 以及更旧的版本。

其他说明

  • 该漏洞涉及 ClassLoader 访问,并取决于使用的实际 Servlet 容器。已知 Tomcat 10.0.19、9.0.61、8.5.77 及更早版本存在漏洞。Payara 和 Glassfish 也已知存在漏洞。其他 Servlet 容器也可能存在漏洞。
  • 此问题与用于从请求参数(查询参数或表单数据)填充对象的数据绑定有关。数据绑定用于使用 @ModelAttribute 注释(或可选地不使用)且没有任何其他 Spring Web 注释的控制器方法参数。
  • 此问题与 @RequestBody 控制器方法参数(例如 JSON 反序列化)无关。但是,如果这些方法具有另一个通过数据绑定从查询参数填充的方法参数,则它们可能仍然存在漏洞。

状态

  • 包含修复程序的 Spring Framework 5.3.18 和 5.2.20 已发布。
  • 依赖于 Spring Framework 5.3.18 的 Spring Boot 2.6.6 和 2.5.12 已发布。
  • CVE-2022-22965 已发布。
  • Apache Tomcat 已发布版本 10.0.20、9.0.62 和 8.5.78,这些版本从 Tomcat 端关闭了攻击向量,请参阅 Spring Framework 远程代码执行漏洞,缓解方案

建议的解决方法

首选的应对措施是更新到 Spring Framework 5.3.185.2.20 或更高版本。如果您已执行此操作,则无需任何解决方法。但是,某些用户可能无法快速升级。因此,我们在下面提供了一些解决方法。

请注意,解决方法不一定是互斥的,因为安全措施最好“多管齐下”。

升级 Tomcat

对于在使用不受支持的 Spring Framework 版本的 Tomcat 上运行的旧版应用程序,升级到 Apache Tomcat 10.0.209.0.628.5.78 可以提供足够的保护。但是,这应该被视为一种战术解决方案,主要目标应尽快升级到当前受支持的 Spring Framework 版本。如果您采用这种方法,您还应考虑设置 禁用字段 以实现纵深防御。

降级到 Java 8

如果您既无法升级 Spring Framework 也无法升级 Apache Tomcat,则降级到 Java 8 是一种可行的解决方法。

禁止字段

另一种可行的解决方法是,通过在全局的WebDataBinder上设置disallowedFields来禁用绑定到特定字段。


@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
public class BinderControllerAdvice {

    @InitBinder
    public void setAllowedFields(WebDataBinder dataBinder) {
         String[] denylist = new String[]{"class.*", "Class.*", "*.class.*", "*.Class.*"};
         dataBinder.setDisallowedFields(denylist);
    }

}

这通常有效,但作为一种集中应用的解决方法,可能会留下一些漏洞,特别是如果控制器通过其自己的@InitBinder方法在本地设置disallowedFields,这会覆盖全局设置。

为了以更安全的方式应用此解决方法,应用程序可以扩展RequestMappingHandlerAdapter,以便在所有其他初始化完成后更新WebDataBinder。为此,Spring Boot 应用程序可以声明一个WebMvcRegistrations bean(Spring MVC)或一个WebFluxRegistrations bean(Spring WebFlux)。

例如,在 Spring MVC 中(WebFlux 中类似)

package car.app;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.InitBinderDataBinderFactory;
import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory;


@SpringBootApplication
public class MyApp {


	public static void main(String[] args) {
		SpringApplication.run(CarApp.class, args);
	}


	@Bean
	public WebMvcRegistrations mvcRegistrations() {
		return new WebMvcRegistrations() {
			@Override
			public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
				return new ExtendedRequestMappingHandlerAdapter();
			}
		};
	}


	private static class ExtendedRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {

		@Override
		protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> methods) {

			return new ServletRequestDataBinderFactory(methods, getWebBindingInitializer()) {

				@Override
				protected ServletRequestDataBinder createBinderInstance(
						Object target, String name, NativeWebRequest request) throws Exception {
					
					ServletRequestDataBinder binder = super.createBinderInstance(target, name, request);
					String[] fields = binder.getDisallowedFields();
					List<String> fieldList = new ArrayList<>(fields != null ? Arrays.asList(fields) : Collections.emptyList());
					fieldList.addAll(Arrays.asList("class.*", "Class.*", "*.class.*", "*.Class.*"));
					binder.setDisallowedFields(fieldList.toArray(new String[] {}));
					return binder;
				}
			};
		}
	}
}

对于没有使用 Spring Boot 的 Spring MVC,应用程序可以从扩展@EnableWebMvc切换到直接扩展DelegatingWebMvcConfiguration,如文档的高级配置部分所述,然后覆盖createRequestMappingHandlerAdapter方法。

误解

关于弃用SerializationUtils的提交,有一些猜测。此类在框架内只有一个用法,并且不会暴露给外部输入。弃用与该漏洞无关。

Spring Cloud Function 的 CVE 存在混淆,该 CVE 在发布此漏洞报告之前发布。它也无关。

获取 Spring 时事通讯

与 Spring 时事通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您快速提升技能。

了解更多

获取支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一个简单的订阅。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部