Dubbo3序列化安全机制导致的一次生产故障

前言

记录一次 Dubbo 线上故障排查和原因分析。

线上 Dubbo 消费者启动有错误日志如下,但是不影响服务启动。

java.lang.TypeNotPresentException: Type org.example.model.ThirdParam not present
...
Caused by: java.lang.ClassNotFoundException: org.example.model.ThirdParam
...

紧接着,消费者发起 RPC 调用,偶发性报错如下:

Caused by: org.apache.dubbo.remoting.RemotingException: 
Failed to send message Request [id=-7672337589162309142, version=2.0.2, twoWay=true, event=false, broken=false, mPayload=0, data=null] to /192.168.98.92:20880, 
cause: org.apache.dubbo.common.serialize.SerializationException: 
java.lang.IllegalArgumentException: [Serialization Security] 
Serialized class org.example.api.InnerParam is not in allow list. 
Current mode is `STRICT`, will disallow to deserialize it by default. 
Please add it into security/serialize.allowlist or follow FAQ to configure it.

消费者尝试重启,RPC 调用偶尔成功,偶尔失败,没有规律。

故障重现

为了重现故障,我写了个示例工程,有四个模块:

  • third-sdk

模拟依赖的三方 SDK,有两个版本:V1.0 V2.0,区别是 ThirdParam 类只在 V2.0 才提供。

  • dubbo-api

Dubbo API 模块,包含服务接口和参数类,依赖third-sdk V2.0

  • dubbo-provider

Dubbo 服务提供者,直接依赖dubbo-api,间接依赖third-sdk V2.0

  • dubbo-consumer

Dubbo 服务消费者,直接依赖dubbo-api,直接依赖third-sdk V1.0

重点:dubbo-consumer 模块自身依赖了低版本的**<font style="color:#DF2A3F;">third-sdk</font>**,ThirdParam 类是不存在的。

dubbo-api模块,IService 接口如下。InnerParam 类存在于当前模块,ThirdParam 来自三方库。

由于dubbo-consumer模块依赖的是低版本的third-sdk,所以 ThirdParam 类不存在,但只要不调用 M2 就没事。

public interface IService {String M1(InnerParam innerParam);String M2(Optional<ThirdParam> optional);
}

ServiceImpl.java和服务提供者的启动和消费者的调用均不是重点,这里不贴代码。

说明:为啥 M2 参数类型是Optional<ThirdParam>

因为如果参数类型直接是 ThirdParam,消费者启动时,解析 Service Class 这一步就会因为 Class Not Found 直接报错而退出进程。ThirdParam 必须是泛型,才不至于 Service Class 无法解析。

接着,启动 Provider,启动 Consumer,就能看到错误日志,但是不影响消费者启动。

再接着,Consumer 发起 RPC 调用,就会报错:

最快的修复方式,重构 IService.java ,方法名 M1 改为 a1

public interface IService {String a1(InnerParam innerParam);String M2(Optional<ThirdParam> optional);
}

接着,重启 Provider,Consumer。Consumer 启动依然有错误日志,但是不影响启动。

Consumer 发起 a1 的 RPC 调用,成功,不再报错。

call a1 start...
call a1 result: OK

为什么仅仅修改个方法名,RPC 调用就不再报错了呢?

故障分析

已知,Dubbo 从 3.1.6 版本开始,为了避免序列化引起的 RCE 攻击,引入了“序列化类检查机制”。只有在信任白名单里的类,才允许被序列化和反序列化。

同时,为了避免开发者手动添加白名单带来的额外负担,Dubbo 默认开启“自动信任机制”。即 Dubbo 会在 Service 暴露和引用的同时,自动信任 Service Class 依赖的相关类,这些类包括:Service Class 本身、父类和接口类型、属性类型、方法的所有入参/出参类型、异常类型等,将它们全部加入到白名单里。

根据消费者报错的信息来看,很明显提示org.example.api.InnerParam类不在白名单里面,所以序列化失败。

cause: org.apache.dubbo.common.serialize.SerializationException: 
java.lang.IllegalArgumentException: [Serialization Security] 
Serialized class org.example.api.InnerParam is not in allow list. 

由此我们推测,Dubbo 的“自动信任机制”出现了问题

通过源码我们发现,Service 在暴露和引用的时候,默认会注册 Service Class,方法是SerializeSecurityConfigurator#registerInterface

注册接口就是将 Service Class 自身、以及超类、属性类、方法的入参/出参、返回类型、异常类型等通通加入到白名单。

public synchronized void registerInterface(Class<?> clazz) {/*** 是否自动信任序列化类?默认是true* 默认会将 Service Class 涉及到的类加入白名单,全部信任*/if (!autoTrustSerializeClass) {return;}Set<Type> markedClass = new HashSet<>();/*** 1. 信任 Service Class 自身* 2. 根据 TrustSerializeClassLevel 信任所在包的层级* 3. 信任 Service Class 的接口、父类、属性类型、*/checkClass(markedClass, clazz);addToAllow(clazz.getName());Method[] methodsToExport = clazz.getMethods();// 信任 Service Class 方法的入参、出参类型、抛出的异常类型for (Method method : methodsToExport) {Class<?>[] parameterTypes = method.getParameterTypes();for (Class<?> parameterType : parameterTypes) {checkClass(markedClass, parameterType);}Type[] genericParameterTypes = method.getGenericParameterTypes();for (Type genericParameterType : genericParameterTypes) {checkType(markedClass, genericParameterType);}Class<?> returnType = method.getReturnType();checkClass(markedClass, returnType);Type genericReturnType = method.getGenericReturnType();checkType(markedClass, genericReturnType);Class<?>[] exceptionTypes = method.getExceptionTypes();for (Class<?> exceptionType : exceptionTypes) {checkClass(markedClass, exceptionType);}Type[] genericExceptionTypes = method.getGenericExceptionTypes();for (Type genericExceptionType : genericExceptionTypes) {checkType(markedClass, genericExceptionType);}}
}

Dubbo 会遍历 Service Class 所有方法,依次注册方法的入参、出参到白名单。

问题就出在这个遍历上,因为dubbo-consumer模块直接依赖了third-sdk V1.0,对于方法IService#M2(Optional<ThirdParam>)的入参,ThirdParam 类是不存在的,导致整个注册过程中断跳出,后续方法的参数都没有注册到白名单,进而导致 Consumer 发起 RPC 调用时,参数序列化报错。

另一个问题,为什么方法**IService#M1**重构为**IService#a1**,Consumer 就正常了呢?

这是因为方法签名修改后,导致Class#getMethods返回的 Method 顺序发生了改变,如果a1方法先于M2方法返回,让中断发生在a1方法注册之后,虽然整个注册过程还是会异常,但是org.example.api.InnerParam类已经添加到白名单了,对后续的 RPC 调用当然没有影响。

注意:虽然示例中通过修改方法名来改变**Class#getMethods**返回的 Method 顺序,但是强烈不建议这么做,因为 Java Doc 已经写的非常清楚了,返回的方法数组没有特定顺序,取决于JVM实现。

The elements in the returned array are not sorted and are not in any particular order.

推荐的修复方式,Service Class 所有的方法入参和出参,都不应该直接用三方 SDK 的类,这本身就不规范。在 API 模块新建 DTO 类,把三方类转换成自己的 DTO 类。

尾巴

因为消费者模块和公共 API 模块依赖的三方库版本不同,导致消费者模块缺少一部分类,进而导致消费者在注册 Service Class 方法参数到序列化白名单时,发生异常中断跳出,没有被信任的参数类,一旦序列化就会抛出异常。

又因为Class#getMethods返回的方法顺序并不固定,就会导致方法参数偶尔被信任,偶尔不被信任,所以会出现服务重启后可能又恢复正常的错觉。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96028.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96028.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

centos7 docker离线安装

介绍 本文主要讲了如何在完全没网的情况下安装docker&#xff08;适合于高网络安全要求的企业&#xff09; 本文适用的centos版本&#xff1a; [root0001 temp]# cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core) 采用docker in docker下载依赖 实际试验后&…

东京本社招聘 | 财务负责人 多个日本IT岗位(Java/C++/Python/AWS 等),IT营业同步招募

大家好&#xff0c;本期为大家带来我司在东京GSD本社及其他会社千叶地区的招聘岗位。 涵盖 财务负责人、Java开发工程师、数据中心维护工程师、项目经理、IT营业 等多个职位。 欢迎有志之士加入&#xff01;&#x1f539; 财务负责人&#xff08;東京本社&#xff09;工作内容日…

四数之和

目录 一&#xff1a;题目链接 二&#xff1a;题目思路 三&#xff1a;代码实现 一&#xff1a;题目链接 理解题目需要注意&#xff0c;如果两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#xff0c;选择其中一个四元组即可。比如 [ 0 , 1 , 0 , 2] 和 [ 1 , …

【序列晋升】29 Spring Cloud Task 微服务架构下的轻量级任务调度框架

Spring Cloud Task作为微服务架构中的轻量级任务调度框架&#xff0c;为开发人员提供了一种构建短生命周期微服务任务的便捷方式。它允许开发者快速创建、执行和管理一次性任务或短期批处理作业&#xff0c;任务执行完成后自动关闭以释放系统资源&#xff0c;避免了传统长期运行…

【1分钟速通】 HTML快速入门

HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09; 是构建网页的基础语言。它通过 标签&#xff08;Tag&#xff09; 来描述网页的结构和内容&#xff0c;常与 CSS&#xff08;负责样式 – <style></style>&#xff09;和 JavaScr…

【GeoServer】WMS GetFeatureInfo URL 逐个参数解释

我来把你构造的这个 WMS GetFeatureInfo URL 逐个参数解释一下&#xff0c;方便你理解&#xff1a;http://127.0.0.1:8090/geoserver/xxxx/wms? SERVICEWMS& VERSION1.1.1& REQUESTGetFeatureInfo& QUERY_LAYERSloess:yourLayer& LAYERSloess:yourLayer& …

OBS直播教程:点歌直播间怎么弄?直播点歌用什么软件?

OBS直播教程&#xff1a;点歌直播间怎么弄&#xff1f;直播点歌用什么软件&#xff1f; 第一步&#xff1a;安装OBS直播软件&#xff0c;如果你电脑已经安装了OBS&#xff0c;请直接看第二步 OBS直播软件下载地址①&#xff1a; https://d.obscj.com/obs-Studio-29.1.3-Full-…

【数据库】Redis详解:内存数据库与缓存之王

什么是Redis&#xff1f; Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、基于内存的数据结构存储系统&#xff0c;可以用作数据库、缓存和消息代理。它支持多种数据结构&#xff0c;如字符串、哈希、列表、集合、有序集合等&#xff0c;具有极高的性能和…

【iOS】 单例模式

1. 认识单例模式首先让我们先看下关于单例模式的定义&#xff08;来自于《设计模式》(Addison-Wesley,1994)&#xff09;一个类有且仅有一个实例&#xff0c;并且自行实例化向整个系统提供。如果说每一个人都是一个类&#xff0c;那么从他出生开始&#xff0c;他就是生活中的唯…

多目标轮廓匹配

前面我们使用模板匹配&#xff0c;得到的结果都是一个图&#xff0c;那么如果我们图片中有许多我们的目标&#xff0c;那么该如何找出来呢&#xff1f;如上我们图片中有许多箭头和我们的模板一致&#xff0c;只不过方向不对&#xff0c;那么该如何匹配呢&#xff1f;图片和模板…

【C++】简单介绍lambda表达式

各位大佬好&#xff0c;我是落羽&#xff01;一个坚持不断学习进步的学生。 如果您觉得我的文章还不错&#xff0c;欢迎多多互三分享交流&#xff0c;一起学习进步&#xff01; 也欢迎关注我的blog主页: 落羽的落羽 文章目录一、 什么是lambda表达式二、 表达式语法三、lambd…

磁共振成像原理(理论)4:自由进动和弛豫 (Free Precession and Relaxation)

当磁化自旋系统被射频脉冲扰动而偏离其热平衡态后&#xff0c;一旦移除外部激励并给予足够时间&#xff0c;系统将根据热力学定律返回平衡态。这一过程包含三个特征现象&#xff1a; (a) 自由进动——宏观磁化矢量 (M⃗\vec{M}M) 绕( B0⃗\vec {B_0}B0​​ )场的进动&#xff1…

ubuntu 20.04 安装spark

安装openjdk21 下载 wget https://download.java.net/openjdk/jdk21/ri/openjdk-2135_linux-x64_bin.tar.gz解压 tar -xvf openjdk-2135_linux-x64_bin.tar.gzsudo mv jdk-21/ /opt/jdk-21/设置环境变量 echo export JAVA_HOME/opt/jdk-21 | sudo tee /etc/profile.d/java2…

第三方区块链应用测评:【多签钱包合约安全评估_阈值签名机制与私钥存储安全性测试】

阈值签名机制安全测试密码学审计 采用门限签名方案&#xff08;TSS&#xff09;的多签钱包需验证其阈值BLS签名或ECDSA签名算法的正确性。测试重点包括&#xff1a;分布式密钥生成&#xff08;DKG&#xff09;过程的保密性&#xff08;无密钥信息泄露&#xff09;、签名碎片验证…

大模型处理长文档的挑战和解决方案?

当前&#xff0c;AI 应用正处于极速发展阶段&#xff0c;大语言模型&#xff08;LLM&#xff09;与检索增强生成&#xff08;RAG&#xff09;系统已成为构建智能问答、知识管理等高阶 AI 应用的核心引擎&#xff0c;被广泛应用于金融分析、学术研究、企业合规等多个领域。然而&…

JavaWeb--day1--HTMLCSS

(以下内容全部来自上述课程及课件) web开发介绍 1. 什么是web&#xff1f; Web&#xff1a;全球广域网&#xff0c;也称为万维网&#xff0c;能够通过浏览器访问的网站。 2. Web网站的工作流程 3. Web标准 Web标准也称为网页标准&#xff0c;由一系列的标准组成&#xf…

OpenEuler安装gitlab,部署gitlab-runner

目录 一、安装gitlab 二、安装部署docker设置源 三、下载部署runner ​编辑 四、构建CI/CD 一、安装gitlab 1.查看OpenEuler版本 [rootlocalhost ~]# cat /etc/os-release NAME"openEuler" VERSION"24.03 (LTS-SP1)" ID"openEuler" VERSI…

实战项目-----在图片 hua.png 中,用红色画出花的外部轮廓,用绿色画出其简化轮廓(ε=周长×0.005),并在同一窗口显示

实战项目实现以下功能&#xff1a;对图片 hua.png 进行轮廓提取&#xff0c;并在同一窗口中完成以下两个绘制操作&#xff1a;用红色画出花的外部轮廓&#xff08;即最外层轮廓&#xff09;用绿色画出该轮廓的近似多边形&#xff0c;其中近似精度参数 ε 设置为轮廓周长的 0.00…

开源鸿蒙北向框架开发:系统服务理论详解

系统服务的启动 基本可以认为&#xff1a;OpenHarmony 的系统服务进程都是“由 init 直接或间接拉起”的。 直接方式&#xff1a; init 按 /system/etc/init/.cfg 启动可执行&#xff08;如 /system/bin/sa_main、/system/bin/samgr 等&#xff09;&#xff0c;这些进程的 PPid…

龙虎榜——20250909

上证指数今天缩量收阴线&#xff0c;跌破10日均线&#xff0c;目前日线总体处于高位宽幅震荡中&#xff0c;小级别暂未明确方向&#xff0c;指数面临方向选择&#xff0c;需要注意高位股的风险。 深证指数今天缩量收阴线&#xff0c;跌破5日均线&#xff0c;接下来几天方向的选…