当前位置: 首页 > news >正文

fastjson-流程分析

参考视频:fasfjson反序列化漏洞1-流程分析

分析版本

fastjson1.2.24

JDK 8u65

分析过程

新建Person类

public class Person {private String name;private int age;public Person() {System.out.println("constructor_0");}public Person(String name, int age) {this.name = name;this.age = age;System.out.println("constructor_2");}public String getName() {System.out.println("getName");return name;}public void setName(String name) {this.name = name;System.out.println("setName");}public int getAge() {System.out.println("getAge");return age;}public void setAge(int age) {this.age = age;System.out.println("setAge");}
}

新建JSONTest

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;public class JSONTest {public static void main(String[] args) throws Exception {String s = "{\"@type\":\"Person\",\"age\":18,\"name\":\"tttt\"}";JSONObject jsonObject = JSON.parseObject(s);System.out.println(jsonObject);}
}

image-20240715102848791

发现parseObject(s)过程还调用了get方法。详细的过程可以跟一下上面视频。

分析下fastjson的JSON.parseObject(s);逻辑

主要逻辑在DefaultJSONParser的parse方法

public static Object parse(String text, int features) {if (text == null) {return null;}DefaultJSONParser parser = new DefaultJSONParser(text, ParserConfig.getGlobalInstance(), features);Object value = parser.parse();    //主要的逻辑在这儿parser.handleResovleTask(value);parser.close();return value;
}

parse()先进行字符串的匹配

case LBRACE: //匹配到左大括号JSONObject object = new JSONObject(lexer.isEnabled(Feature.OrderedField));return parseObject(object, fieldName);

之后进入parseObject

key是@type,进入此循环,fastjson会尝试将字符串反序列化为输入的@type类。可以看到进入循环之后会调用loadCLass方法,加载类

image-20240715142244242

TypeUtils.loadClass对输入进行了预处理,不处理的话loadClass默认是不能加载数组类的

image-20240715143333345

加载完类之后,继续往下跟。到下面的位置会进行反序列化,跟进去

image-20240715143853109

public ObjectDeserializer getDeserializer(Type type) {ObjectDeserializer derializer = this.derializers.get(type);  //首先查看有没有符合条件的默认的反序列化器,我们自己写的类,肯定是返回nullif (derializer != null) {return derializer;}if (type instanceof Class<?>) {return getDeserializer((Class<?>) type, type);   //之后进入这个方法}if (type instanceof ParameterizedType) {Type rawType = ((ParameterizedType) type).getRawType();if (rawType instanceof Class<?>) {return getDeserializer((Class<?>) rawType, type);} else {return getDeserializer(rawType);}}return JavaObjectDeserializer.instance;
}

getDeserializer((Class<?>) type, type);方法中,找不到符合条件的反序列化器,则把传入的默认当作JavaBean。

image-20240715145213169

在createJavaBeanDeserializer中又调用到了JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, type, propertyNamingStrategy);

通过这个build方法去获取Person的信息,从而创建Person的反序列化器。

这里不详细写了

下面三个循环,第一个寻找public的set方法,第二个寻找public的属性,第三个寻找public的get方法(如果有了对应的set方法,那么这里不在创建get方法)

image-20240715151747655

fastjson还有一个设定是,如果找到了某个属性的set方法,那么get方法就不再add。这个操作是在最后一个循环的下面这里实现的。

image-20240715164947894

这里要说一下根据上面分析,如果针对某个属性只有getter方法,则会创建getter方法,但是fastjson对getter方法的返回值做了判断,需要满足下面条件

image-20240731102641050

之后我们就拿到了需要的反序列化器(这有个关于debug的问题,大家看视频吧,这儿就不写了,更新了Person类)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//import java.util.Map;public class Person {private String name;private int age;private Map map;public Person() {System.out.println("constructor_0");}public Person(String name, int age) {this.name = name;this.age = age;System.out.println("constructor_2");}public String getName() {System.out.println("getName");return this.name;}public void setName(String name) {this.name = name;System.out.println("setName");}public int getAge() {System.out.println("getAge");return this.age;}public void setAge(int age) {this.age = age;System.out.println("setAge");}public Map getMap() {System.out.println("getMap");return this.map;}
}

下面可以跟一下反序列化器JavaBeanDeserializer中,是如何调用构造函数,set和get方法的。

在反序列化器JavaBeanDeserializer中,只会调用setAge和setName。不会调用getAge和getName方法(上面讲了原因)和getMap(这是因为在JavaBeanDeserializer中做了判断)

} else if (fieldClass == float[][].class) {   //上面还有很多类型的判断,但是没有Map类,所以这里为假fieldValue = lexer.scanFieldFloatArray2(name_chars);if (lexer.matchStat > 0) {matchField = true;valueParsed = true;} else if (lexer.matchStat == JSONLexer.NOT_MATCH_NAME) {continue;}
} else if (lexer.matchField(name_chars)) {  //检查map是否在JSON中matchField = true;
} else {continue;
}

我们想要输出getMap改一下JSON就行了。String s = "{\"@type\":\"Person\",\"age\":18,\"name\":\"tttt\",\"map\":{}}";这样就能输出getMap了。

剩下的getAge和getName是在JSON.toJSON(obj);中完成输出的。

///JSON
public static JSONObject parseObject(String text) {Object obj = parse(text);if (obj instanceof JSONObject) {return (JSONObject) obj;}return (JSONObject) JSON.toJSON(obj);
}
///JSON
if (serializer instanceof JavaBeanSerializer) {JavaBeanSerializer javaBeanSerializer = (JavaBeanSerializer) serializer;JSONObject json = new JSONObject();try {Map<String, Object> values = javaBeanSerializer.getFieldValuesMap(javaObject);for (Map.Entry<String, Object> entry : values.entrySet()) {json.put(entry.getKey(), toJSON(entry.getValue()));}} catch (Exception e) {throw new JSONException("toJSON error", e);}return json;
}

利用

下面弹个计算器试试

一、注意类里面都没有定义map这个属性,但是因为fastjson是按set和get等方法寻找属性的,所以并不影响。

要注意setMap中参数必须为1,否则fastjson会报错

public class Test {public void setMap(String map) throws IOException {Runtime.getRuntime().exec("calc");}
}
public class JSONTest {public static void main(String[] args) throws Exception {String s = "{\"@type\":\"Test\",\"map\":\"aaaa\"}";JSONObject jsonObject = JSON.parseObject(s);System.out.println(jsonObject);}
}

二、get方法注意不能有参数

public class Test {public Map getMap() throws IOException { //如果返回类型改为int的话,需要在JSON语句中加入map的赋值,否则不会执行get方法。这样做程序可以在toJSON中执行get方法Runtime.getRuntime().exec("calc");return new HashMap();}
}
public class JSONTest {public static void main(String[] args) throws Exception {String s = "{\"@type\":\"Test\"}";JSONObject jsonObject = JSON.parseObject(s);System.out.println(jsonObject);}
}

如果getMap返回类型是Map,而且JSON中还给map赋值了。那么会运行两次getMap(我的Test类里面没有setMap方法)

第一次是在形成反序列化器时

第二次是在toJSON中。

相关文章:

fastjson-流程分析

参考视频&#xff1a;fasfjson反序列化漏洞1-流程分析 分析版本 fastjson1.2.24 JDK 8u65 分析过程 新建Person类 public class Person {private String name;private int age;public Person() {System.out.println("constructor_0");}public Person(String na…...

Linux 命令安装

系列文章目录 提示&#xff1a;仅用于个人学习&#xff0c;进行查漏补缺使用。 1.Linux介绍、目录结构、文件基本属性、Shell 2.Linux常用命令 3.Linux文件管理 4.Linux 命令安装 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助…...

清华和字节联合推出的视频理解大模型video-SALMONN(ICML 2024)

video-SALMONN: Speech-Enhanced Audio-Visual Large Language Models 论文信息 paper&#xff1a;https://arxiv.org/abs/2406.15704 code&#xff1a;https://github.com/bytedance/SALMONN/ AI也会「刷抖音」&#xff01;清华领衔发布短视频全模态理解新模型 | ICML 2024 …...

从数据爬取到可视化展示:Flask框架与ECharts深度解析

目录 &#x1f539; Flask框架源码解析 Flask应用初始化路由与视图函数请求与响应中间件 &#x1f539; ECharts可视化精讲 ECharts安装与配置基本图表类型图表样式与交互高级图表配置与数据动态更新实战&#xff1a;结合Flask与ECharts展示爬取数据 Flask框架源码解析 &…...

【jvm】类加载分几步

目录 1. 加载&#xff08;Loading&#xff09;2. 链接&#xff08;Linking&#xff09;2.1 验证&#xff08;Verification&#xff09;2.2 准备&#xff08;Preparation&#xff09;2.3 解析&#xff08;Resolution&#xff09; 3. 初始化&#xff08;Initialization&#xff0…...

使用Apache http client发送json数据(demo)

POM依赖 &#xff1a; <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.12</version></dependency><dependency><groupId>com.alibaba</groupId&g…...

读零信任网络:在不可信网络中构建安全系统07设备信任

1. 设备信任 1.1. 在零信任网络中建立设备信任至关重要&#xff0c;这也是非常困难的一个环节 1.2. 建立设备信任是基石&#xff0c;直接影响零信任网络架构的成败 1.3. 大多数网络安全事件都和攻击者获得信任设备的控制权相关&#xff0c;这种情况一旦发生&#xff0c;信任…...

【Java算法专场】前缀和(下)

目录 和为 K 的子数组 算法分析 算法步骤 算法代码 算法示例 和可被 K 整除的子数组 算法分析 同余定理 负数取余 算法步骤 算法代码 算法示例 连续数组 算法分析 算法步骤 算法代码 算法示例 矩阵区域和 算法分析 算法步骤 算法代码 算法示例 算法分析 …...

音视频相关文章总目录

为了方便各位观看&#xff0c;本文置顶&#xff0c;以目录形式汇集我写过的大部分音视频专题文章。之后文章更新&#xff0c;本目录也会同步更新。写得不好和零零散散的文章就不放在这里了&#x1f605; &#xff1a; 音视频入门基础&#xff1a;像素格式专题系列文章&#x…...

7月31日MySQL学习笔记

今日内容: mysql: 行列转换 数据类型 函数 触发器 存储过程 事务 索引(还没讲) 三范式 JDBC连接数据库的6个步骤 三握四挥 行列转换 第一步 新建要转换的列 select name, 1 as 语文, 1 as 数学, 1 as 英语 from t_score GROUP BY name 第二步 对每一列填入值…...

什么是容器查询?分享 1 段优质 CSS 代码片段!

本内容首发于工粽号&#xff1a;程序员大澈&#xff0c;每日分享一段优质代码片段&#xff0c;欢迎关注和投稿&#xff01; 大家好&#xff0c;我是大澈&#xff01; 本文约 700 字&#xff0c;整篇阅读约需 1 分钟。 今天分享一段优质 CSS 代码片段&#xff0c;使用容器查询…...

【linux深入剖析】初识线程---线程概念

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1. Linux线程概念什么是线…...

【MySQL】索引——索引的引入、认识磁盘、磁盘的组成、扇区、磁盘访问、磁盘和MySQL交互、索引的概念

文章目录 MySQL1. 索引的引入2. 认识磁盘2.1 磁盘的组成2.2 扇区2.3 磁盘访问 3. 磁盘和MySQL交互4. 索引的概念4.1 索引测试4.2 Page4.3 单页和多页情况 MySQL 1. 索引的引入 海量表在进行普通查询的时候&#xff0c;效率会非常的慢&#xff0c;但是索引可以解决这个问题。 -…...

python部署flask项目

python部署flask项目 1. 准备服务器2. 设置服务器环境3. 创建虚拟环境并安装项目依赖4. 配置Gunicorn5. 配置Nginx6. 设置Supervisor&#xff08;可选&#xff09;7. 测试部署 将Flask项目部署到服务器的流程大致如下&#xff1a; 1. 准备服务器 首先&#xff0c;需要准备一台…...

数据建模标准-基于事实建模

前情提要 数据模型定义 DAMA数据治理体系中将数据模型定义为一种文档形式&#xff0c;数据模型是用来将数据需求从业务传递到IT,以及在IT内部从分析师、建模师和架构师到数据库设计人员和开发人员的主要媒介&#xff1b; 作用 记录数据需求和建模过程中产生的数据定义&…...

量产部落SM2258XT开卡软件,SM2258XT主控128G SSD固态卡死修复

故障现象&#xff1a;连接此固态硬盘后电脑就会卡死&#xff0c;拔掉重新连接概率性显示盘符&#xff0c;显示了之后也不能正常操作&#xff0c;一点击打开&#xff0c;电脑就立马卡死。 解决过程&#xff1a;下载了很多款量产工具&#xff0c;都不能开卡成功&#xff0c;点击…...

《零散知识点 · 自定义 HandleMapping》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…...

谈谈我对微服务的理解2.0

文章目录 一、引出问题二、微服务2-1、微服务的技术2-2、微服务的目的 三、微服务的拆分四、不连表查询五、微服务的好处六、微服务的坏处七、应付当下 这篇文章原本叫《如何做到不连表查询》&#xff0c;因为我对这个事一直耿耿于怀。在上家公司我经常被连表折磨&#xff08;连…...

ECCV 2024前沿科技速递:GLARE-基于生成潜在特征的码本检索点亮低光世界,低光环境也能拍出明亮大片!

在计算机视觉与图像处理领域&#xff0c;低光照条件下的图像增强一直是一个极具挑战性的难题。暗淡的光线不仅限制了图像的细节表现&#xff0c;还常常引入噪声和失真&#xff0c;极大地影响了图像的质量和可用性。然而&#xff0c;随着ECCV 2024&#xff08;欧洲计算机视觉会议…...

前端低代码必备:FrontendBlocks 4.0版本重磅发布,助力Uniapp-X原生APP开发

项目介绍 本软件是一款强大的所见即所得前端页面设计器&#xff0c;是低代码开发领域的基础设施&#xff0c;生成的代码不依赖于任何框架&#xff0c;实测可以将前端布局工作的耗时减少80%以上&#xff0c;最关键的是&#xff0c;它实现了人人都可以写前端页面的梦想。 不用写…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要

根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分&#xff1a; 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

redis和redission的区别

Redis 和 Redisson 是两个密切相关但又本质不同的技术&#xff0c;它们扮演着完全不同的角色&#xff1a; Redis: 内存数据库/数据结构存储 本质&#xff1a; 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能&#xff1a; 提供丰…...