一、背景
spring boot 修复 Spring Framework URL解析不当漏洞(CVE-2024-22243)
1、漏洞描述
当应用程序使用UriComponentsBuilder来解析外部提供的URL(如通过查询参数)并对解析的URL的主机执行验证检查时可能容易受到Open重定向攻击和SSRF攻击,导致网络钓鱼和内部网络探测等。
2、受影响产品或系统
6.1.0 <= Spring Framework <= 6.1.3
6.0.0 <= Spring Framework <= 6.0.16
5.3.0 <= Spring Framework <= 5.3.31
3、官方建议修复方案
Spring Framework 版本6.1.x 用户:升级到 6.1.4
Spring Framework 版本6.0.x 用户:升级到 6.0.17
Spring Framework 版本5.3.x 用户:升级到 5.3.32
springboot升级到3.1.9或者3.2.3
其它已经不受官方支持的版本(5.1.x,5.2.x)同样受到影响,更新到受官方支持的安全版本。
因为我们的系统是2.7.11,所以尝试升级到最新的版本3.2.3。
一、升级过程
1、复制项目
由于2到3改动太大,升级不一定成功,所以这里复制一份项目,复制完后记得修改下pom.xml的项目名称
2、修改springboot的版本依赖
这里将2.7.11改到3.2.3
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!-- <version>2.7.11</version> -->
<version>3.2.3</version>
</parent>
重新编译
3、启动测试
不要管报错,直接启动测试,发现jdk版本不对
Exception in thread "main" java.lang.UnsupportedClassVersionError: org/springframework/boot/SpringApplication has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
1、2019年1月15日发布的Oracle JDK 8u201和8u202是最后一个免费版本,后续的都是收费的
2、springboot3.x后最少都要jdk17,所以这里只能用开源的openjdk17或者RedHatOpenJDK17
4、替换servlet的相关import
springboot3.x后用的是jakarta,所以也没上所有涉及这些引入的地方全部都要改动
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
改为
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
包括但不限于上面三个,这边几乎在所有Controller和service的页面都有修改,所以就没个页面都打开替换了一下,最后再看,但是一开始会发现没有这些依赖,这里需要再pom.xml引入
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
</dependency>
eclipse并不会立即提示那些类没有引入,可能是我eclipse版本的原因,只能一个个改,有时候还会没有任何反应,启动也启动不了,这时只能重启
5、org/yaml/snakeyaml/inspector/TagInspector的错误
这里上面一步骤后还会有写类报错,这里暂时不处理先,直接先启动发现
17:15:09.565 [restartedMain] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.NoClassDefFoundError: org/yaml/snakeyaml/inspector/TagInspector
Caused by: java.lang.IllegalStateException: java.lang.NoClassDefFoundError: org/yaml/snakeyaml/inspector/TagInspector
at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:825)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:344)
at com.gdpost.activity.mgr.AppActivityMGR.main(AppActivityMGR.java:23)
... 5 more
这个需要再pom.xml引入
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.2</version>
</dependency>
6、日志冲突
启动后会报一连串日志冲突错误
The following method did not exist:
'void org.apache.logging.log4j.util.PropertiesUtil.addPropertySource(org.apache.logging.log4j.util.PropertySource)'
The calling method's class, org.springframework.boot.logging.log4j2.Log4J2LoggingSystem, was loaded from the following location:
jar:file:/D:/Software/repository/org/springframework/boot/spring-boot/3.2.3/spring-boot-3.2.3.jar!/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.class
The called method's class, org.apache.logging.log4j.util.PropertiesUtil, is available from the following locations:
我这里是把相关引入的日志注释
<!-- <dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency> -->
具体每个系统具体分析,这里还把其它应用日志的版本也去掉才行,不然好像还报如下错误
ERROR StatusLogger Unable to create Lookup for ctx
java.lang.NoSuchMethodError: 'java.lang.ClassLoader[] org.apache.logging.log4j.util.LoaderUtil.getClassLoaders()'
7、 Invalid value type for attribute ‘factoryBeanObjectType’:
TRACE StatusConsoleListener AsyncLoggerConfig[org.springframework.context.annotation.ConfigurationClassPostProcessor] stopping...
[2024-03-07 17:22:13,114]-[ERROR]-[restartedMain]-[org.springframework.boot.SpringApplication]-[]-Application run failed
java.lang.IllegalArgumentException: Invalid value type for attribute 'factoryBeanObjectType': java.lang.String’
这个错误需要将mybatis的版本修改
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<!-- <version>2.2.2</version> -->
<version>3.0.3</version>
</dependency>
8、tomcat版本错误
'void org.apache.catalina.Context.addServletContainerInitializer(jakarta.servlet.ServletContainerInitializer, java.util.Set)'
The calling method's class, org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory, was loaded from the following location:
jar:file:/D:/Software/repository/org/springframework/boot/spring-boot/3.2.3/spring-boot-3.2.3.jar!/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactory.class
The called method's class, org.apache.catalina.Context, is available from the following locations:
jar:file:/D:/Software/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.73/tomcat-embed-core-9.0.73.jar!/org/apache/catalina/Context.class
springboot3.x后。tomcat版本也要对应修改,我这边是因为制定了版本,去掉指定即可
<properties>
<!--<tomcat.version>8.5.77</tomcat.version>-->
<!-- <tomcat.version>9.0.65</tomcat.version> -->
<!-- <tomcat.version>9.0.73</tomcat.version> -->
</properties>
9、redis链接错误
严重: Servlet.service() for servlet [dispatcherServlet] in context with path [/activitymgr] threw exception
org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.translateException(LettuceConnectionFactory.java:1795)
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1726)
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getNativeConnection(LettuceConnectionFactory.java:1528)
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.lambda$getConnection$0(LettuceConnectionFactory.java:1508)
at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.doInLock(LettuceConnectionFactory.java:1469)
这个是因为springboot3以后的版本redis配置变了
sring.redis变为spring.data.redis
10、 javax.xml.bind.DatatypeConverter找不到
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter
... 94 more
jakarta.servlet.ServletException: Handler dispatch failed: java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
pm.xml加上
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
11、freemarker页面取session的值的问题
发现freemarker直接取session取不了了,要从session中取出来然后设置到request中
12、sun.misc.BASE64Encoder和sun.misc.BASE64Decoder的替代
这两个类是sun公司的内部方法,并没有在java api中公开过,不属于JDK标准库范围,java8后已经弃用了,这里可以用java.util。Base64来替代
Base64.Encoder base64Encoder = Base64.getEncoder();
Base64.Decoder base64Decoder = Base64.getDecoder();
12、GLIBC版本问题
Error: dl failure on line 542
Error: failed /home/ssmuser/activity_mgr_new/jdk-17.0.2/lib/server/libjvm.so, because /lib64/libc.so.6: version `GLIBC_2.6' not found (required by /home/ssmuser/activity_mgr_new/jdk-17.0.2/lib/server/libjvm.so)
jdk17需要2.6的版本,但是目前系统的版本是2.5.
查看目前系统的版本
ldd --version
ldd (GNU libc) 2.5
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
尝试备份服务器升级到2.6
tar -zxvf glibc-2.6.tar.gz
mkdir build
cd build
../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin
make && make install
继续启动程序然后报缺失2.7,继续尝试升级,然后执行jps等java命令直接报段错误,尝试重启虚拟机,也不行
13、生成环境glibc版本
发现生产环境glibc版本为2.12,有机会,但是开发环境也要搞定才行。
二、直接升级结果失败
代码升级成功,本地启动测试成功,开发环境启动jdk17发现GLIBC需要2.7,开发环境为2.5升级到2.7后相关java启动命令报段错误,暂时没有解决,生成环境GLIBC为2.12,估计更加难升级2.7. 因此除非服务器环境支持,否则难以升级到springboot3.2.3的版本。
三、替换相关jar包升级
<!-- spring-web 相关 begin -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>5.3.32</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.32</version>
</dependency>
<!-- spring-web相关 end -->
该方案可行。
四、结论
如果你的服务器GLIBC能升级到2.7可以尝试直接升级版本,如果不行可能就得升级相关jar包。当然升级相关jar包的后果就是你的springboot以后也很难从2.x到3.x了。