Fastjsonfan反序列化(一)
前置知识
Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象。
Fastjson 可以操作任何 Java 对象,即使是一些预先存在的没有源码的对象(通过远程调用的方式)
//序列化
String text = JSON.toJSONString(obj);
//反序列化
VO vo = JSON.parse(); //解析为JSONObject类型或者JSONArray类型
VO vo = JSON.parseObject("{...}"); //JSON文本解析成JSONObject类型
VO vo = JSON.parseObject("{...}", VO.class); //JSON文本解析成VO.class类
对象转字符串(序列化)
实体类User
package org.example;
public class User {
public int id;
public String name;
public int age;
public User() {
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
定义一个测试类
package org.example;
import org.example.User;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class Test {
public static void main(String[] args) {
User user = new User();
user.setId(1);
user.setName("zhangsan");
user.setAge(18);
//对象转字符串
String s1 = JSON.toJSONString(user);
String s2 = JSON.toJSONString(user, SerializerFeature.WriteClassName);
System.out.println(s1);
System.out.println(s2);
}
}
输出结果
{"age":18,"id":1,"name":"zhangsan"}
{"@type":"org.example.User","age":18,"id":1,"name":"zhangsan"}
字符串转对象(反序列化)
package org.example;
import org.example.User;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class fastjsonTest {
public static void main(String[] args) {
User user = new User();
user.setId(1);
user.setName("zhangsan");
user.setAge(18);
//对象转字符串
String s1 = JSON.toJSONString(user);
String s2 = JSON.toJSONString(user, SerializerFeature.WriteClassName);
System.out.println(s1);
System.out.println(s2);
System.out.println("s1==========================s1");
//字符串转对象
Object o1 = JSON.parse(s1);
JSONObject jo1 = JSON.parseObject(s1);
User user1 = JSON.parseObject(s1, User.class);
System.out.println(o1);
System.out.println(jo1);
System.out.println(user1);
System.out.println("s2=========================s2");
Object o2 = JSON.parse(s2);
JSONObject jo2 = JSON.parseObject(s2);
User user2 = JSON.parseObject(s2, User.class);
System.out.println(o2);
System.out.println(jo2);
System.out.println(user2);
}
}
输出结果
{"age":18,"id":1,"name":"zhangsan"}
{"@type":"org.example.User","age":18,"id":1,"name":"zhangsan"}
s1==========================s1
{"name":"zhangsan","id":1,"age":18}
{"name":"zhangsan","id":1,"age":18}
User{id=1, name='zhangsan', age=18}
s2=========================s2
User{id=1, name='zhangsan', age=18}
{"name":"zhangsan","id":1,"age":18}
User{id=1, name='zhangsan', age=18}
fastjson通过JSON.toJSONString()将对象转为字符串(序列化),当使用SerializerFeature.WriteClassName参数时会将对象的类名写入@type字段中,在重新转回对象时会根据@type来指定类,进而调用该类的set、get方法。因为这个特性,我们可以指定@type为任意存在问题的类,造成一些问题
利用
漏洞是利用fastjson autotype在处理json对象的时候,未对@type字段进行完全的安全性验证,攻击者可以传入危险类,并调用危险类连接远程rmi主机,通过其中的恶意类执行代码。攻击者通过这种方式可以实现远程代码执行漏洞的利用,获取服务器的敏感信息泄露,甚至可以利用此漏洞进一步对服务器数据进行修改,增加,删除等操作,对服务器造成巨大的影响。
set,get,is自动调用问题
构造Evil类
package org.example;
public class Evil {
private String cmd;
public Evil(){
System.out.println("Evil()"+ this.hashCode());
}
public String getCmd() {
System.out.println("getCmd()"+this.hashCode());
return cmd;
}
public void setCmd(String cmd) {
System.out.println("setCmd"+this.hashCode());
this.cmd = cmd;
}
}
写一个test测试下
package org.example;
import com.alibaba.fastjson.JSON;
public class Test {
public static void main(String[] args) {
String evil = "{\"@type\":\"org.example.Evil\",\"cmd\":\"calc\"}";
JSON.parse(evil);
System.out.println("-------------------");
JSON.parseObject(evil);
System.out.println("------------------");
JSON.parseObject(evil, Object.class);
}
}

跟进parseObject(evil)发现其方法发现也是使用parse解析的,但是多了一个(JSONObject)toJSON(obj)
这个方法调用的get,堆栈如下
getCmd:11, Evil (org.example)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
get:451, FieldInfo (com.alibaba.fastjson.util)
getPropertyValue:105, FieldSerializer (com.alibaba.fastjson.serializer)
getFieldValuesMap:439, JavaBeanSerializer (com.alibaba.fastjson.serializer)
toJSON:902, JSON (com.alibaba.fastjson)
toJSON:824, JSON (com.alibaba.fastjson)
parseObject:206, JSON (com.alibaba.fastjson)
main:13, Test (org.example)
那么setter在哪调用的?
在com.alibaba.fastjson.util.JavaBeanInfo#build中

在通过@type拿到类之后,通过反射拿到该类所有的方法存入methods,接下来遍历methods进而获取get、set方法,如上图。总结set方法自动调用的条件为:
- 方法名长度大于4
- 非静态方法
- 返回值为void或当前类
- 方法名以set开头
- 参数个数为1
当满足条件之后会从方法名截取属性名,截取时会判断_,如果是set_name会截取为name属性,具体逻辑如下:

当截取完但是找不到这个属性

会判断传入的第一个参数类型是否为布尔型,是的话就在截取完的变量前加上is,截取propertyName的第一个字符转大写和第二个字符,并且然后重新尝试获取属性字段。
比如:public boolean setBoy(boolean t) 会寻找isBoy字段。
set的整个判断就是:如果有setCmd()会绑定cmd属性,如果该类没有cmd属性会绑定isCmd属性。
get的判断

总结下就是:
- 方法名长度大于等于4
- 非静态方法
- 以get开头且第4个字母为大写
- 无传入参数
- 返回值类型继承自Collection Map AtomicBoolean AtomicInteger AtomicLong
当程序绑定了对应的字段之后,如果传入json字符串的键值中存在这个值,就会去调用执行对应的setter、构造方法
小结:
- parse(jsonStr) 构造方法+Json字符串指定属性的setter()+特殊的getter()
- parseObject(jsonStr) 构造方法+Json字符串指定属性的setter()+所有getter() 包括不存在属性和私有属性的getter()
- parseObject(jsonStr,Object.class) 构造方法+Json字符串指定属性的setter()+特殊的getter()
Fastjsonfan反序列化(一)的更多相关文章
- C#反序列化XML异常:在 XML文档(0, 0)中有一个错误“缺少根元素”
Q: 在反序列化 Xml 字符串为 Xml 对象时,抛出如下异常. 即在 XML文档(0, 0)中有一个错误:缺少根元素. A: 首先看下代码: StringBuilder sb = new Stri ...
- C# 序列化与反序列化几种格式的转换
这里介绍了几种方式之间的序列化与反序列化之间的转换 首先介绍的如何序列化,将object对象序列化常见的两种方式即string和xml对象; 第一种将object转换为string对象,这种比较简单没 ...
- 迟来的Json反序列化
源码发布 搞了一个下午,终于搞定了这个号称中国的github...以后源码直接在这里发布了(github实在用不来,英文实在太烂了) https://code.csdn.net/jy02305022/ ...
- .Net使用Newtonsoft.Json.dll(JSON.NET)对象序列化成json、反序列化json示例教程
JSON作为一种轻量级的数据交换格式,简单灵活,被很多系统用来数据交互,作为一名.NET开发人员,JSON.NET无疑是最好的序列化框架,支持XML和JSON序列化,高性能,免费开源,支持LINQ查询 ...
- 使用Newtonsoft.Json.dll(JSON.NET)动态解析JSON、.net 的json的序列化与反序列化(一)
在开发中,我非常喜欢动态语言和匿名对象带来的方便,JSON.NET具有动态序列化和反序列化任意JSON内容的能力,不必将它映射到具体的强类型对象,它可以处理不确定的类型(集合.字典.动态对象和匿名对象 ...
- 【.NET深呼吸】如何反序列化动态JSON
.net本身除了支持SOAP.XML.二进制等序列化和反序列化,后来也加入了对JSON的序列化的支持.然而,在实际开发中,常常会遇到结构不确定的JSON对象,这些对象可能是其他代码动态生成的,你事先无 ...
- Java 序列化与反序列化
1.什么是序列化?为什么要序列化? Java 序列化就是指将对象转换为字节序列的过程,而反序列化则是只将字节序列转换成目标对象的过程. 我们都知道,在进行浏览器访问的时候,我们看到的文本.图片.音频. ...
- C#中怎样实现序列化和反序列化
我们想要将数据进行持久化的操作的话,也就是将数据写入到文件中,我们在C#中可以通过IO流来操作,同时也可以通过序列化来操作,本人是比较推荐使用序列化操作的 因为我们如果想要将一个对象持久化到文件中 如 ...
- Java序列化与反序列化
Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨. 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列 ...
- 让Visual Studio 2013为你自动生成XML反序列化的类
Visual Sutdio 2013增加了许多新功能,其中很多都直接提高了对代码编辑的便利性.如: 1. 在代码编辑界面的右侧滚动条上显示不同颜色的标签,让开发人员可以对所编辑文档的修改.查找.定位情 ...
随机推荐
- Hive的基本知识与操作
Hive的基本知识与操作 目录 Hive的基本知识与操作 Hive的基本概念 为什么使用Hive? Hive的特点: Hive的优缺点: Hive应用场景 Hive架构 Client Metastor ...
- ELK套件部署
前言 经过两周的不断碰壁,版本的选择 最终选择ELK的7.6.1套餐 因为我所需要的的警报插件sentinl也才跟新到7.6.1 运行环境:centos7 需要开放的端口:5601,9200,514( ...
- 从零打造“乞丐版” React(一)——从命令式编程到声明式编程
这个系列的目的是通过使用 JS 实现"乞丐版"的 React,让读者了解 React 的基本工作原理,体会 React 带来的构建应用的优势 1 HTML 构建静态页面 使用 HT ...
- 5.云原生之Docker容器网络介绍与实践
转载自:https://www.bilibili.com/read/cv15185166/?from=readlist 例如, 当在一台未经过特殊网络配置的centos 或 ubuntu机器上安装完d ...
- Kibana插件
附加的功能在 Kibana 中是以插件的形式提供的.您可以利用 bin/kibana-plugin 命令来管理这些模块.您也可以手动安装这些插件,只需要将这些插件包放到 plugins 目录并解压到新 ...
- Kibana探索数据(Discover)详解
设置时间过滤器 时间过滤器按照指定的时间段展示搜索结果.设置了 index contains time-based events 和 time-field 的索引模式可以使用时间过滤器. 时间过滤器默 ...
- 升级Gogs版本
今天早上收到阿里云发的报警短信,大致内容如下: 前提分析: 公司代码代码仓库使用是Gogs搭建的,版本是0.11.34,二进制方式安装的,连接的是其他主机上的MySQL数据库,因此被检测到有这个漏洞 ...
- Docker Compose的安装及命令补全
安装Compose Compose的安装有多种方式,例如通过shell安装.通过pip安装.以及将compose作为容器安装等等.本文讲解通过shell安装的方式.其他安装方式如有兴趣,可以查看Doc ...
- windows下mysql的数据主主同步
mysql主主备份: 保证各服务器上的数据库中的数据一致,因此需要开启数据库同步机制.由于是一整套系统,并且系统内含数据库.由于任何一台服务器都有可能被选中,因此要让所有的数据库上的数据都是最新的,任 ...
- PAT (Basic Level) Practice 1008 数组元素循环右移问题 分数 20
一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A0A1⋯AN−1)变换为(AN−M⋯AN−1A0A1⋯AN ...