Spring Framework RCE,早期公告

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

更新

目錄

概覽

我在此宣佈 Spring Framework 中存在一個 RCE 漏洞,該漏洞在 CVE 釋出之前被提前洩露。該問題最早於格林威治時間週二深夜接近午夜時由螞蟻集團 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 RCE,緩解替代方案

建議的臨時解決方案

首選的應對措施是更新到 Spring Framework 5.3.185.2.20 或更高版本。如果已完成此操作,則無需其他臨時解決方案。但是,某些情況下可能無法快速升級。因此,我們在下方提供了一些臨時解決方案。

請注意,臨時解決方案不一定是互斥的,因為安全措施最好是“縱深防禦”。

升級 Tomcat

對於在 Tomcat 上執行且使用不受支援的 Spring Framework 版本的舊應用,升級到 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 產生了混淆。它也與此無關。

獲取 Spring 新聞通訊

訂閱 Spring 新聞通訊保持聯絡

訂閱

搶佔先機

VMware 提供培訓和認證,助力您快速提升。

瞭解更多

獲得支援

Tanzu Spring 透過單一訂閱提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援及二進位制檔案。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視全部