springboot版本升级以及解决springsecurity漏洞的问题
作者:喜羊羊love红太狼
背景
项目中要解决 Spring Security RegexRequestMatcher 认证绕过漏洞(CVE-2022-22978) 漏洞问题,并且需要将项目的版本整体升级到boot版本2.1.7,升级改造过程非常的痛苦,一方面对整个框架的代码不是很熟悉,另外对解决漏洞问题相对较少。
需求
解决Spring Security RegexRequestMatcher 认证绕过漏洞(CVE-2022-22978) 漏洞,升级boot版本2.1.7
改造前父pom如下(部分依赖省略):
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.gisquest.realestate</groupId> <artifactId>gisqrealestate-unityplatform-core</artifactId> <version>2.2.1.RELEASE</version> <modules> <module>unityplatform-security</module> <module>unityplatform-microauth</module> <module>unityplatform-apigateway</module> <module>unityplatform-servicediscovery</module> <module>unityplatform-microappadmin</module> <module>unityplatform-apigateway-core</module> <module>unityplatform-apigateway-app</module> <module>unityplatform-microauth-app</module> <module>unityplatform-core-comm</module> </modules> <packaging>pom</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring-boot-admin.version>1.5.6</spring-boot-admin.version> <jjwt.version>0.7.0</jjwt.version> <commons-lang3.version>3.3.2</commons-lang3.version> <swagger2.version>2.7.0</swagger2.version> <apollo-client.version>1.0.0</apollo-client.version> <jackson.version>2.10.2</jackson.version> <!--micro version--> <micro-apigateway.version>2.2.1.RELEASE</micro-apigateway.version> <micro-auth.version>2.2.1.RELEASE</micro-auth.version> <micro-comm.version>2.2.1.RELEASE</micro-comm.version> <micro-apigateway.img.version>2.2.RELEASE</micro-apigateway.img.version> <micro-auth.img.version>2.2.RELEASE</micro-auth.img.version> <micro.img.version>2.2.RELEASE</micro.img.version> <com.hanweb.SecurityUtil.version>1.0</com.hanweb.SecurityUtil.version> <!--XStream --> <xstream.version>1.4.20</xstream.version> <spring.version>5.3.20</spring.version> <spring-security.version>5.5.8</spring-security.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>Brussels-SR7</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
漏洞解决方案
gisqrealestate-unityplatform-core 项目下 解决Spring Security RegexRequestMatcher 认证绕过漏洞(CVE-2022-22978) 漏洞
升级boot版本2.1.7(和快速构建保持一致)
注意下升级之后一些配置文件(例如redis,文件限制大小等) 和 代码 不兼容问题
漏洞影响版本
5.5.0 <= Spring Security < 5.5.7
5.6.0 <= Spring Security < 5.6.4
版本改造问题
改造前 版本
<spring-cloud.version>Edgware.SR2</spring-cloud.version> <spring-boot.version>1.5.10.RELEASE </spring-boot.version>
升级到2.x版本
<spring-cloud.version>Greenwich.SR2</spring-cloud.version> <spring-boot.version>2.1.7.RELEASE</spring-boot.version>
问题一:项目改造前是自定义的springboot依赖,现要求去掉原先的自定义封装依赖
刚开始我是把原先自定义的springboot依赖的父依赖直接移到最外层,大概过程如下,导致出现一堆问题。
坑一:类不存在,或包不存在
项目中出现大量的类不存在,但是明明可以用鼠标点击进去,此类问题经常是idea,什么缓存,或者是pom依赖下载不全导致,然后就陷入了这个误区,一直以为是idea的问题。
先是清理 idea缓存、执行mvn idea:idea命令等方式很多次还是无法解决。
然后分支代码提交后,同事检出也是同样的问题,项目还是无法启动,保错也是提示类不存在等。
此时我就怀疑可能不是idea的问题了。
后面就换了一种方式
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.10.RELEASE</version> <relativePath /> </parent>
改成
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency>
改成这样后终于正常了,不在提示类不存在,包不存在等问题了。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <groupId>com.gisquest.realestate</groupId> <artifactId>gisqrealestate-unityplatform-core</artifactId> <version>2.2.1.RELEASE</version> <modelVersion>4.0.0</modelVersion> <packaging>pom</packaging> <modules> <module>unityplatform-security</module> <module>unityplatform-microauth</module> <module>unityplatform-apigateway</module> <module>unityplatform-servicediscovery</module> <module>unityplatform-microappadmin</module> <module>unityplatform-apigateway-core</module> <module>unityplatform-apigateway-app</module> <module>unityplatform-microauth-app</module> <module>unityplatform-core-comm</module> </modules> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring-boot-admin.version>1.5.6</spring-boot-admin.version> <jjwt.version>0.7.0</jjwt.version> <commons-lang3.version>3.3.2</commons-lang3.version> <swagger2.version>2.7.0</swagger2.version> <apollo-client.version>1.0.0</apollo-client.version> <jackson.version>2.10.2</jackson.version> <!--micro version--> <micro-apigateway.version>2.2.1.RELEASE</micro-apigateway.version> <micro-auth.version>2.2.1.RELEASE</micro-auth.version> <micro-comm.version>2.2.1.RELEASE</micro-comm.version> <micro-apigateway.img.version>2.2.RELEASE</micro-apigateway.img.version> <micro-auth.img.version>2.2.RELEASE</micro-auth.img.version> <micro.img.version>2.2.RELEASE</micro.img.version> <com.hanweb.SecurityUtil.version>1.0</com.hanweb.SecurityUtil.version> <!--XStream --> <xstream.version>1.4.19</xstream.version> <spring-cloud.version>Greenwich.SR2</spring-cloud.version> <spring-boot.version>2.1.7.RELEASE</spring-boot.version> <eureka.version>2.1.0.RELEASE</eureka.version> <openfeign.version>2.0.0.RELEASE</openfeign.version> <zuul.version>2.1.2.RELEASE</zuul.version> <commons-lang.version>2.6</commons-lang.version> <commons-collections.version>3.2.2</commons-collections.version> <commons-beanutils.version>1.9.3</commons-beanutils.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </project>
坑二:idea中maven设置,最好调整成maven运行(推荐)
否则会出现稀奇古怪的问题,比如上面的之前用parent依赖方式我本地可以跑(奇了怪),但是同事拉下拉却跑不了,切换成eclipse也同样项目跑不起来。
经过一番折腾代码是跑起来了总算不提示类不存等问题。
代码兼容问题
org.springframework.data.redis.serializer.SerializationException: Cannot deserialize
org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.InvalidClassException: org.springframework.security.core.authority.SimpleGrantedAuthority; local class incompatible: stream classdesc serialVersionUID = 420, local class serialVersionUID = 510
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:84) ~[spring-data-redis-2.1.10.RELEASE.jar!/:2.1.10.RELEASE]
解决方法:
redis跨版本升级后,需要把redis缓存清理一下
问题一:alibaba.fastjson.JSONObject cannot be cast to xx
java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to com.gisquest.realestate.security.validate.code.ValidateCode
- 改造前逻辑
@Override public ValidateCode get(ServletWebRequest request, ValidateCodeType validateCodeType) { Object object = redisTemplate.opsForValue().get(buildKey(request, validateCodeType)); if (object == null) { return null; } return (ValidateCode)object ; }
- 改造后
@Override public ValidateCode get(ServletWebRequest request, ValidateCodeType validateCodeType) { Object object = redisTemplate.opsForValue().get(buildKey(request, validateCodeType)); if (object == null) { return null; } String josn =JSON.toJSONString(object); return JSONObject.parseObject(josn,ValidateCode.class); }
问题解决!!!!
问题二:升级后通过feign调用认证服务接口/oauth/check_token接口提示如下
Illegal hexadecimal character - at index 8
org.apache.commons.codec.DecoderException: Illegal hexadecimal character - at index 8
at org.apache.commons.codec.binary.Hex.toDigit(Hex.java:286)
at org.apache.commons.codec.binary.Hex.decodeHex(Hex.java:106)
at com.gisquest.realestate.utils.Encodes.decodeHex(Encodes.java:41)
原因版本问题
改造前spring-security-core-4.2.4.RELEASE
在AbstractUserDetailsAuthenticationProvider在实现类中additionalAuthenticationChecks方法逻辑如下
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { Object salt = null; if (this.saltSource != null) { salt = this.saltSource.getSalt(userDetails); } if (authentication.getCredentials() == null) { logger.debug("Authentication failed: no credentials provided"); throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } String presentedPassword = authentication.getCredentials().toString(); if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) { logger.debug("Authentication failed: password does not match stored value"); throw new BadCredentialsException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } }
- 改造后
spring-security-core-5.1.6.RELEASE版本中AbstractUserDetailsAuthenticationProvider在实现类中改方法additionalAuthenticationChecks
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { if (authentication.getCredentials() == null) { this.logger.debug("Authentication failed: no credentials provided"); throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } else { String presentedPassword = authentication.getCredentials().toString(); if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { this.logger.debug("Authentication failed: password does not match stored value"); throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } } }
逻辑变化了
使用了自定义的密码加密类
密码加密方式发现不一样了,因此按照原先代码逻辑获取到的前后密码其实是一样的,但是升级后GisqPasswordEncoder起了作用,因此在比较时应该时加密后的匹配
因此改成这样
问题三:feign调用token校验接口,在项目中未搜索到
后来打断点才发现竟然后spring-security-oaruth2包内部类CheckTokenEndpoint中的接口,无语,我还以为是自己定义的呢找了半天未找打!!!!!
jar包依赖冲突问题
方式一:选择依赖的模块,鼠标右键,选择show dependency
如果有冲突会出现报红!!!
方式二:安装一个maven-helper插件
如果有冲突会自动显示,然后去排处即可
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。