多次触发FastJson漏洞的AutoType机制,你了解吗?

2023-12-24 19:52

本文主要是介绍多次触发FastJson漏洞的AutoType机制,你了解吗?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一个反序列化问题

在一次日志巡检过程中,发现线上业务出现报错。线上业务场景是:调用三方restful接口,根据接口返回json字符串内容,进行反序列化处理,业务中使用的json处理工具是FastJson(v1.2.71)。

报错是使用fastJson进行反序列化时出现的,问题json字符串如下:

{"name":"","error":{"@type":"xxx.xxx.ErrorType","message":"xxxxx"}
}

从数据结构上看,这个json字符串并没有什么特殊性,就是一个普通的字符串而已。从内容上看,比较特殊的地方在于多了一个特殊的字段“@type”,经过测试,反序列化报错,的确是因为这个特殊的字段造成的(把@type字段去掉,反序列化可以正常进行)。

那么@type是什么鬼,为什么有了字段就会产生问题呢?

@type和AutoType

使用过json序列化工具,处理包含接口、抽象类等无法直接实例化的字段类型时,你是否想过这些序列化工具是如何进行反序列化的吗?如果没有看明白这个问题的话,可以看一下下面的代码实例。

static class VehicleStore {private String name;private Vehicle vehicle;// 省略 setter/getter}interface Vehicle {}static class Car implements Vehicle {private BigDecimal price;// 省略 setter/getter}

上面代码定义了一个比较简单的数据类型,VehicleStore类中包含了一个类型是接口Vehicle 的字段 vehicle,接口Vehicle有一个实现类Car。

使用FastJson对VehicleStore进行序列化。

@Testpublic void deserializer() {VehicleStore store = new VehicleStore();store.setName("vehicleStore");Car car = new Car();car.setPrice(new BigDecimal(5000000));store.setVehicle(car);String jsonString = JSON.toJSONString(store);}

序列化后的json字符串内容如下:

 {"name":"vehicleStore","vehicle":{"price":5000000}}

在这个反序列化后的字符串内容中,vehicle字段的内容是 {“price”:5000000} ,无论从内容上、还是结构上看,根本看不出 {“price”:5000000} 和类型Car,有什么关系,那么用这个json字符串,进行反序列化,如何反序列化出 VehicleStore,并且把字段vehicle指定为Car呢?

其实是不能的,如果直接用FastJson进行反序列化,反序列化出来的VehicleStore中vehicle字段是空(没有任何字段内容)。
在这里插入图片描述

总结来说:当一个类中包含了一个接口(或抽象类),在使用fastjson进行序列化的时候,会将子类型抹去,只保留接口(抽象类)的类型,使得反序列化时无法拿到原始类型

为了解决这个问题,在fastjson中引入了AutoType机制,简单来说,既然无法正常反序列化是序列化时把原始类型擦除掉了导致的,那么在序列化时,把类型信息给添加上可以了。的确,FastJson也是这样做的,具体做法如下:

序列化:
在进行序列化时,使用

JSON.toJSONString(xxxObj, SerializerFeature.WriteClassName);

序列化出来的内容会带上"@type"字段,记录被序列化的类型,弥补类型擦除的问题。序列化后,内容如下:

{"@type":"com.test.FastJsonTest$VehicleStore","name":"vehicleStore","vehicle":{"@type":"com.test.FastJsonTest$Car","price":5000000}}

反序列化:
反序列化时使用@type字段完成对子类/实现类的实例化,然后,再将相应的字段内容通过setter方法注入到实例化后的对象中,完成反序列化。

完整实例代码:


@Testpublic void deserializer() {VehicleStore store = new VehicleStore();store.setName("vehicleStore");Car car = new Car();car.setPrice(new BigDecimal(5000000));store.setVehicle(car);String jsonString = JSON.toJSONString(store, SerializerFeature.WriteClassName); VehicleStore newStore = JSON.parseObject(jsonString, VehicleStore.class);Car car = (Car) newStore.getVehicle();}

问题解决

到这里在文章开头,遇到的@type是怎么回事儿,也就清楚了。那么为什么带上@type后,反序列化会报错呢?这里我直接说一下答案:直接原因是@type指定的类型,在系统中不存在,在反序列化时,找不到该类型。

解决问题的方法也很简单,既然@type指定的类型不存在,那么可以在系统中把需要的类型定义出来,不过@type指定的类型,是三方接口系统中定义的,如果把该类型引入到调用方系统中,那么对于调用方的侵入性很大,而且定义这个类型,仅仅为了解决这个问题,有很大解释成本在里面。

第二种解决方案:在反序列化时,忽略@type字段,这需要在反序列化时,添加Feature.IgnoreAutoType,完整的配置方式如下:

VehicleStore newStore1 = JSON.parseObject(jsonStr, VehicleStore.class, Feature.IgnoreAutoType);

到这里,开头的问题已经得到了解决,但是了解了AutoType机制后,你是否想过,如果把@Type指定为一个比较“特殊”的类型,有可能会对系统的安全产生比较大的威胁。

比如,把@type指定一个jdk中自带的类型 com.sun.rowset.JdbcRowSetImpl ,同时把字段dataSourceName设置为一个rmi数据源,那么对rmi数据源进行解析时,就完成了对rmi的调用,实现了对系统的远程命令执行。

具体操作过程如下(此漏洞,已修复,无法复现了,哈哈哈)

public void setDataSourceName(String var1) throws SQLException {if (this.getDataSourceName() != null) {if (!this.getDataSourceName().equals(var1)) {super.setDataSourceName(var1);// 注入攻击rmi源this.conn = null;this.ps = null;this.rs = null;}} else {super.setDataSourceName(var1);}} private Connection connect() throws SQLException {if (this.conn != null) {return this.conn;} else if (this.getDataSourceName() != null) {try {InitialContext var1 = new InitialContext();DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());// 调用rmi方法return this.getUsername() != null && !this.getUsername().equals("") ? var2.getConnection(this.getUsername(), this.getPassword()) : var2.getConnection();} catch (NamingException var3) {throw new SQLException(this.resBundle.handleGetObject("jdbcrowsetimpl.connect").toString());}} else {return this.getUrl() != null ? DriverManager.getConnection(this.getUrl(), this.getUsername(), this.getPassword()) : null;}}

其实FastJson的很多安全漏洞都和AutoType有关,当黑客发现了一个漏洞后,作者会立即进行相应的修复,在安全的攻防过程中,fastJson对AutoType进行了多个版本的更新:

1.2.59发布,增强AutoType打开时的安全性 fastjson
1.2.60发布,增加了AutoType黑名单,修复拒绝服务安全问题 fastjson
1.2.61发布,增加AutoType安全黑名单 fastjson
1.2.62发布,增加AutoType黑名单、增强日期反序列化和JSONPath fastjson
1.2.66发布,Bug修复安全加固,并且做安全加固,补充了AutoType黑名单 fastjson
1.2.67发布,Bug修复安全加固,补充了AutoType黑名单 fastjson
1.2.68发布,支持GEOJSON,补充了AutoType黑名单。(引入一个safeMode的配置,配置safeMode后,无论白名单和黑名单,都不支持autoType。) fastjson
1.2.69发布,修复新发现高危AutoType开关绕过安全漏洞,补充了AutoType黑名单 fastjson
1.2.70发布,提升兼容性,补充了AutoType黑名单

对此过程有感兴趣的老铁可以阅读一下下面这个文章:https://juejin.cn/post/6846687594130964488

这篇关于多次触发FastJson漏洞的AutoType机制,你了解吗?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/532935

相关文章

一文详解Java异常处理你都了解哪些知识

《一文详解Java异常处理你都了解哪些知识》:本文主要介绍Java异常处理的相关资料,包括异常的分类、捕获和处理异常的语法、常见的异常类型以及自定义异常的实现,文中通过代码介绍的非常详细,需要的朋... 目录前言一、什么是异常二、异常的分类2.1 受检异常2.2 非受检异常三、异常处理的语法3.1 try-

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

SpringRetry重试机制之@Retryable注解与重试策略详解

《SpringRetry重试机制之@Retryable注解与重试策略详解》本文将详细介绍SpringRetry的重试机制,特别是@Retryable注解的使用及各种重试策略的配置,帮助开发者构建更加健... 目录引言一、SpringRetry基础知识二、启用SpringRetry三、@Retryable注解

SpringKafka错误处理(重试机制与死信队列)

《SpringKafka错误处理(重试机制与死信队列)》SpringKafka提供了全面的错误处理机制,通过灵活的重试策略和死信队列处理,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、Spring Kafka错误处理基础二、配置重试机制三、死信队列实现四、特定异常的处理策略五

java中反射(Reflection)机制举例详解

《java中反射(Reflection)机制举例详解》Java中的反射机制是指Java程序在运行期间可以获取到一个对象的全部信息,:本文主要介绍java中反射(Reflection)机制的相关资料... 目录一、什么是反射?二、反射的用途三、获取Class对象四、Class类型的对象使用场景1五、Class

一文带你了解SpringBoot中启动参数的各种用法

《一文带你了解SpringBoot中启动参数的各种用法》在使用SpringBoot开发应用时,我们通常需要根据不同的环境或特定需求调整启动参数,那么,SpringBoot提供了哪些方式来配置这些启动参... 目录一、启动参数的常见传递方式二、通过命令行参数传递启动参数三、使用 application.pro

一文带你深入了解Python中的GeneratorExit异常处理

《一文带你深入了解Python中的GeneratorExit异常处理》GeneratorExit是Python内置的异常,当生成器或协程被强制关闭时,Python解释器会向其发送这个异常,下面我们来看... 目录GeneratorExit:协程世界的死亡通知书什么是GeneratorExit实际中的问题案例

如何关闭 Mac 触发角功能或设置修饰键? mac电脑防止误触设置技巧

《如何关闭Mac触发角功能或设置修饰键?mac电脑防止误触设置技巧》从Windows换到iOS大半年来,触发角是我觉得值得吹爆的MacBook效率神器,成为一大说服理由,下面我们就来看看mac电... MAC 的「触发角」功能虽然提高了效率,但过于灵敏也让不少用户感到头疼。特别是在关键时刻,一不小心就可能触

Nginx之upstream被动式重试机制的实现

《Nginx之upstream被动式重试机制的实现》本文主要介绍了Nginx之upstream被动式重试机制的实现,可以通过proxy_next_upstream来自定义配置,具有一定的参考价值,感兴... 目录默认错误选择定义错误指令配置proxy_next_upstreamproxy_next_upst

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri