➜ Old React website
Chung Cheuk Hang MichaelJava Web Developer
Spring Security 漏洞 CVE-2023-34034客製化 JRE

Spring Security 漏洞 CVE-2023-20860

Table of contents

1 CVE-2023-20860 背景

今年 Snyk 公佈左一個新既 Spring 安全漏洞,叫做 SNYK-JAVA-ORGSPRINGFRAMEWORK-3369852,對應 CVE 資料庫既 CVE-2023-20860

1.1 涉及既 library 版本

呢個漏洞係同 org.springframework:spring-webmvc 有關。有問題既版本包括 [5.3.0,5.3.26)[6.0.0,6.0.7),亦即係:
  • 5.3.05.3.25
  • 6.0.06.0.6
已修復既版本包括:
  • 5.3.26 或以上
  • 6.0.7 或以上
註:6.x 係用於 Spring Boot 3.x

1.2 漏洞涉及既安全問題

根據 CVE 既描述,當使用左 mvcRequestMatcher 配置 Spring Security 既時候用左 un-prefixed double wildcard pattern(**),Spring 背後所產生既實際 Spring MVC 配置會同我地既 Spring Security 有出入,最終有可能導致個 Spring app 允許未經授權既訪問。

2 建立測試項目

2.1 Maven dependencies

  • Maven parent POM:spring-boot-starter-parent
  • Dependencies
    • spring-boot-starter-web
    • spring-boot-starter-security

2.2 HTTP APIs

Request methodRequest path測試結果期望
GET/public呢個 endpoint 唔應該需要登入驗證。
GET/secure呢個 endpoint 應該需要登入驗證。

2.3 寫 Java code

2.3.1 Controller

BusinessController.java
1@RestController 2public class BusinessController { 3 4 @GetMapping("public") 5 public String _public() { 6 return "This is a public endpoint. You should see this without logging in."; 7 } 8 9 @GetMapping("secure") 10 public String secure() { 11 return "This is a secure endpoint. You should NOT see this without logging in."; 12 } 13}

2.3.2 Spring Security config class

SecurityConfiguration.java
1@Configuration 2public class SecurityConfiguration { 3 4 @Bean 5 public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 6 return http 7 .authorizeHttpRequests().mvcMatchers("/public").permitAll() 8 .and() 9 .authorizeHttpRequests().mvcMatchers("/**").authenticated() 10 .and() 11 .httpBasic() 12 .and() 13 .build(); 14 } 15}
另一個寫法:
1@Configuration 2public class SecurityConfiguration { 3 4 @Bean 5 public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 6 return http 7 .authorizeHttpRequests() 8 .mvcMatchers("/public").permitAll() 9 .mvcMatchers("/**").authenticated() 10 .and() 11 .httpBasic() 12 .and() 13 .build(); 14 } 15}
再另一個寫法:
1@Configuration 2public class SecurityConfiguration { 3 4 @Bean 5 public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 6 return http 7 .authorizeHttpRequests(authorize -> authorize 8 .mvcMatchers("/public").permitAll() 9 .mvcMatchers("/**").authenticated()) 10 .httpBasic() 11 .and() 12 .build(); 13 } 14}

3 測試結果

3.1 使用有漏洞既版本

以下係有漏洞既版本:
  • spring-boot-starter-security 2.7.1
    • Spring Security 5.7.2
  • spring-webmvc 5.3.21

3.1.1 測試結果:Permit 特定 endpoints、authenticate wildcard

  1. mvcMatchers(<some paths>).permitAll()
  2. mvcMatchers(<wildcard>).authenticated()
Implementation解釋結果
Permit public、authenticate **兩者都冇 / 開頭/secure 唔需要登入,存在漏洞。
Permit /public、authenticate /**兩者都有 / 開頭✅ 符合測試結果期望。
Permit public、authenticate /**其中一個有 / 開頭/public 需要登入,過分安全。
Permit /public、authenticate **其中一個有 / 開頭/secure 唔需要登入,存在漏洞。
Permit public、authenticate *兩者都冇 / 開頭,單 * 字元/secure 唔需要登入,存在漏洞。
Permit /public、authenticate /*兩者都有 / 開頭,單 * 字元✅ 符合測試結果期望。
Permit public、authenticate /*其中一個有 / 開頭,單 * 字元/public 需要登入,過分安全。
Permit /public、authenticate *其中一個有 / 開頭,單 * 字元/secure 唔需要登入,存在漏洞。

3.1.2 測試結果:Authenticate 特定 endpoints、permit wildcard

  1. mvcMatchers(<some paths>).authenticated()
  2. mvcMatchers(<wildcard>).permitAll()
Implementation解釋結果
Authenticate secure、permit **兩者都冇 / 開頭/secure 唔需要登入,存在漏洞。
Authenticate /secure、permit /**兩者都有 / 開頭✅ 符合測試結果期望。
Authenticate secure、permit /**其中一個有 / 開頭/secure 唔需要登入,存在漏洞。
Authenticate /secure、permit **其中一個有 / 開頭✅ 符合測試結果期望。
Authenticate secure、permit *兩者都冇 / 開頭,單 * 字元/secure 唔需要登入,存在漏洞。
Authenticate /secure、permit /*兩者都有 / 開頭,單 * 字元✅ 符合測試結果期望。
Authenticate secure、permit /*其中一個有 / 開頭,單 * 字元/secure 唔需要登入,存在漏洞。
Authenticate /secure、permit *其中一個有 / 開頭,單 * 字元✅ 符合測試結果期望。

3.2 使用已修復既版本

用已修復既 spring-webmvc 版本覆蓋項目現有既版本:
  • spring-boot-starter-security 2.7.1
    • Spring Security (multiple libraries) 5.7.2
  • spring-webmvc 5.3.26

3.2.1 測試結果:Permit 特定 endpoints、authenticate wildcard

  1. mvcMatchers(<some paths>).permitAll()
  2. mvcMatchers(<wildcard>).authenticated()
ImplementationTest case結果
Permit public、authenticate **兩者都冇 / 開頭✅ 符合測試結果期望。
Permit /public、authenticate /**兩者都有 / 開頭✅ 符合測試結果期望。
Permit public、authenticate /**其中一個有 / 開頭✅ 符合測試結果期望。
Permit /public、authenticate **其中一個有 / 開頭✅ 符合測試結果期望。
Permit public、authenticate *兩者都冇 / 開頭,單 * 字元✅ 符合測試結果期望。
Permit /public、authenticate /*兩者都有 / 開頭,單 * 字元✅ 符合測試結果期望。
Permit public、authenticate /*其中一個有 / 開頭,單 * 字元✅ 符合測試結果期望。
Permit /public、authenticate *其中一個有 / 開頭,單 * 字元✅ 符合測試結果期望。

3.2.2 測試結果:Authenticate 特定 endpoints、permit wildcard

  1. mvcMatchers(<some paths>).authenticated()
  2. mvcMatchers(<wildcard>).permitAll()
ImplementationTest case結果
Authenticate secure、permit **兩者都冇 / 開頭✅ 符合測試結果期望。
Authenticate /secure、permit /**兩者都有 / 開頭✅ 符合測試結果期望。
Authenticate secure、permit /**其中一個有 / 開頭✅ 符合測試結果期望。
Authenticate /secure、permit **其中一個有 / 開頭✅ 符合測試結果期望。
Authenticate secure、permit *兩者都冇 / 開頭,單 * 字元✅ 符合測試結果期望。
Authenticate /secure、permit /*兩者都有 / 開頭,單 * 字元✅ 符合測試結果期望。
Authenticate secure、permit /*其中一個有 / 開頭,單 * 字元✅ 符合測試結果期望。
Authenticate /secure、permit *其中一個有 / 開頭,單 * 字元✅ 符合測試結果期望。

4 參考資料