Java反射与Fastjson的危险反序列化

什么是Java反射?

在前文中,我们有一行代码 Computer macBookPro = JSON.parseObject(preReceive,Computer.class);

这行代码是什么意思呢?看起来好像就是我们声明了一个名为 macBookPro 的 Computer 类,它由 fastjson 的 parseObject 方法将 preReceive 反序列化而来,但 Computer.class 是什么呢?

在 Java 中,Computer.class是一个引用,它表示了 Computer 的字节码对象(Class对象),这个对象被广泛应用于反射、序列化等操作中。那么为什么 parseObject 需要这个引用呢?首先 fastjson 是不了解类中的情况的,因此它需要一个方法来动态的获得类中的属性,那么 Java 的反射机制提供了这个功能。

Java reflect demo

我们先看一个 Java 反射的 Demo。

package org.example;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;public class JavaReflectDemo {public static void main(String[] args){// 获取Car类的Class对象,用于后续的反射操作Class<?> temp = Car.class;// 获得Car类的所有属性与方法和构造方法Field[] fields = temp.getDeclaredFields();Method[] methods = temp.getDeclaredMethods();Constructor<?>[] constructors = temp.getDeclaredConstructors();// 通过循环遍历获得类属性for (Field field : fields){System.out.println("Field: " + field.getName());}// 通过循环遍历获得方法名for (Method method : methods ) {System.out.println("Methods: " + method.getName());}// 通过双循环获得类的构造方法及其方法所需要的参数的数据类型for (Constructor<?> constructor : constructors) {System.out.println("Constructor:" + constructor.getName());Class<?>[] constructorParameterType = constructor.getParameterTypes();for (Class<?> parameterType : constructorParameterType) {System.out.println("Parameter type is:" + parameterType.getName());}}// 通过反射调用类方法}public static class Car{private int carLength;public String carName;private int carPrice = 50000;public Car(int carLength, String carName,int carPrice){this.carLength = carLength;this.carName = carName;this.carPrice = carPrice;}private void CarAnnounce() {System.out.println("China Car! Best Car!");System.out.println("The Car Price is " + this.carPrice);System.out.println("The Car Length is " + this.carLength);}private void CarType(){System.out.println("This function is still under development!");}}
}

反射调用类变量

上述代码中,我们有一个公共静态类 Car ,其中包含了私有和公共方法和属性,在主函数中通过反射获取了类的属性和方法以及构造方法,我们逐行分析代码。

  • Class<?> temp = Car.class; 这行代码用于获取 Car 的 Class 对象,Class 对象是整个反射操作的起点。那么 Class<?> 是什么意思呢?其实在这里这个问号指的是 temp 可以接收任意类型的类,我们也可以通过 Class<Car> 来接收 Class 对象。

  • getDeclaredFields() 是 Java 的反射操作,通过 Class 对象获得类中所有的属性,包括私有属性,它返回一个 Field[] 对象,实际上是一个包含类中所有属性的数组,但它被特定为 Field[] 对象。

  • getDeclaredMethods() 同理,获得类中所有的方法(但不包含构造方法),返回一个 Methods[] 数组。

  • getDeclaredConstructors() 用于获得类中所有的构造方法,Constructor<?>[] 的含义是,Constructor 是个泛型类,它的定义是 Constructor<T> ,这意味着它适用于任何类型的构造方法,通过使用通配符 <?> 表示这个数组接收任何类的构造方法,也就是表示了constructors 这个数组可以用于存储任意类的任意构造方法。

  • 获得了数组后,通过 Java 的 for-each 循环遍历数组并打印到屏幕。

运行结果如下。

反射调用类方法

简要将Demo中的代码修改如下。

// 通过循环遍历获得方法名for (Method method : methods) {// 直接调用类的静态方法if (method.getName().equals("CarType")) {method.invoke(null);}// 通过类的实例调用类方法if (method.getName().equals("CarAnnounce")){Car tempCar = new Car(1000,"Richard's car");method.invoke(tempCar);// 通过反射获得类字段,并修改字段值重新调用方法Field field = temp.getDeclaredField("carPrice");field.setAccessible(true);field.set(tempCar, 99999);method.invoke(tempCar);}System.out.println("Methods: " + method.getName());
}

我们可以通过反射直接调用类的方法,method.invoke(类的实例, 参数, 多个参数用逗号隔开),若是调用静态方法可以传递 null 代替类的实例,但如果调用的方法需要参数,我们需要严格得按照方法传入对应的参数。

我们还可以通过反射修改 private 属性,例如 Demo 中的 carPrice。运行结果如下。

我们将 carLength 使用 final 修饰符进行修饰,此时直接修改 carLength 会报错。如下图。

但通过反射我们可以修改 final 修饰符修饰后的属性。代码如下。

Field field2 = temp.getDeclaredField("carLength");
field2.setAccessible(true);Field modifiers = field2.getClass().getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field2, field2.getModifiers() & ~Modifier.FINAL);field2.set(tempCar, 7777);
method.invoke(tempCar);

我们来重点关注其中的操作,我们首先获取 carLength 的 Field 对象,并设置其为可读写的权限。

其次获取该对象的 modifiers 对象,它表示 carLength 被哪些修饰符所修饰。

重点是modifiers.setInt(field2, field2.getModifiers() & ~Modifier.FINAL) 我们逐步进行解析:

  1. modifiers.setInt 对 modifiers 对象进行修改,也就是修改 carLength 的修饰符。

  2. 首先传入实例,重点在其参数,这里实际是一个位操作,getmodifiers() 方法会返回当前对象的修饰符组合,它是由 Java Modifier 类中定义的值所组合起来的。见下图。

  1. 那么 ~Modifier.FINAL 中的 ~ 是对该值取反,0x10 转换为二进制为 0001 0000 取反为 1110 1111& 对其进行与操作,那么实际上就是在去除 FINAL 修饰符。

  2. 最后将其结果修改 modifiers 对象,也就是去除了 FINAL 修饰符。

整段代码的执行结果如下。

反射执行命令

在 Java 中,有一个类叫做 java.lang.Runtime ,这个类有一个 exec 方法可以用于执行本地命令。一般情况下我们使用如下的方法执行命令。我们通过Runtime.getRuntime()方法获得实例,并创建新的Process对象,用于执行命令。

Runtime类是Java中的一个特殊类,它负责提供Java应用程序与运行时环境(Java虚拟机)的交互接口。它被设计为单例模式,确保整个应用程序中只有一个Runtime实例。这种设计决定了Runtime类无法被直接实例化。

package org.example;public class ExecuteCommandDemo {public static void main(String[] args){try {// 创建Runtime对象Runtime temp = Runtime.getRuntime();Process process = temp.exec("calc.exe");// 等待命令执行完毕process.waitFor();} catch (Exception e) {e.printStackTrace();}}
}

而我们同样可以通过反射来执行命令。

首先获取Runtime类对象以便后续的反射操作,再从Runtime类中获取getRuntime方法,通过执行getRuntime方法获取实例,再从类中找到 exec 方法,但由于 exec 具有很多重载版本,我们指定使用接收字符串作为参数的方法。最后通过调用 exec 方法,执行命令。

package org.example;
import java.lang.reflect.Method;public class ExecuteCommandDemo {public static void main(String[] args){try {Class <?> reflectExec = Class.forName("java.lang.Runtime");Method getruntimeMethod = reflectExec.getMethod("getRuntime");Object runtimeInstance = getruntimeMethod.invoke(null);Method execMethod = reflectExec.getMethod("exec", String.class);Process process = (Process) execMethod.invoke(runtimeInstance, "calc.exe");// 等待命令执行完毕process.waitFor();} catch (Exception e) {e.printStackTrace();}}
}

Fastjson的危险反序列化

@type 是fastjson中的一个特殊注解,它告诉 fastjson 应该将 JSON 字符串转换成哪个 Java 类。这很容易出现安全问题

我们来看下面这段代码,我们定义了一串json字符串,想要通过@type注解来将json字符串转化为java.lang.Runtime对象,但是 fastjson在 1.2.24 后默认禁用 autoType 的白名单设置,在默认情况下我们不能任意的将json字符串转化为指定的java类。

但通过 ParserConfig.getGlobalInstance().addAccept("java.lang") 我们可以在白名单中添加 java.lang 类。

后续的代码就是通过反序列化将其转换为对象(这里的Object.class是为了接收转换后的任意对象),再强制转换为Runtime对象,转换完成后就和正常调用java.lang.Runtime执行命令相同了。

package org.example;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;public class FastjsonDangerousDeserialization {public static void main(String[] args) throws Exception{String json = "{\"@type\":\"java.lang.Runtime\"}";ParserConfig.getGlobalInstance().addAccept("java.lang");Runtime runtime = (Runtime) JSON.parseObject(json, Object.class);runtime.exec("calc.exe");}
}

文章转载自:ZywOo

原文链接:https://www.cnblogs.com/RichardLuo/p/18287704/Fastjson_2

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

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

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

相关文章

《梦醒蝶飞:释放Excel函数与公式的力量》10.2 COMPLEX函数

第二节 10.2 COMPLEX函数 10.2.1函数简介 COMPLEX函数是Excel中的一个工程函数&#xff0c;用于将实部和虚部组合成一个复数。复数广泛应用于工程、电气、物理等领域&#xff0c;COMPLEX函数提供了方便的复数表示和计算方法。 10.2.2语法&#xff1a; COMPLEX(real_num, i_…

【LabVIEW学习篇 - 5】:数据类型——数值、字符串

文章目录 数值枚举下拉列表控件 字符串字符串与十六进制截取字符串连接字符串 字符串与数值间的转换字符串转为数值数值转为字符串 数值 如下图所示&#xff0c;各种数值型数据的不同之处在于存储和表示数据时所使用的位置不同。 浮点型 整型 在LabVIEW中&#xff0c;想要改…

JavaScript中的LHS和RHS

LHS和RHS之前我们先来回忆一下最简单的赋值操作! var test100; console.log(test); 以上代码的意思简单我们理解为把右边的值赋值给左边的test变量,然后输出打印结果。 可是我们要是深入理解你就会发现在这个过程当中&#xff0c;还发生了一些其他的事情 而这些事情就是今天…

欧姆龙安全PLC及周边产品要点指南

电气安全、自动化设备作业安全&#xff0c;向来是非常非常之重要的&#xff01;越来越多的客户在规划新产线、改造既有产线的过程中&#xff0c;明确要求设计方和施工方将安全考虑进整体方案中进行考虑和报价&#xff01;作为一名自动化电气工程师&#xff0c;尤其是高级工程师…

养宠经验分享猫咪经常掉毛怎么办?最值得买的宠物空气净化器分享

身为资深铲屎官&#xff0c;深知若偷懒不打扫&#xff0c;家中便成猫毛纷飞、异味缭绕的战场&#xff0c;尤其换季时&#xff0c;更是雪上加霜。长期处于这样的环境&#xff0c;不仅我们头疼眼涩、咳嗽气喘&#xff0c;对老人、小孩、孕妇等敏感群体更是健康大敌。 幸运的是&a…

Vagrant配合VirtualBox搭建虚拟机

目录 前言一、软件下载及安装1.下载2.安装扩展&#xff1a; 二、创建一个虚拟机1.Vagrant官方镜像仓库 三、使用远程工具连接虚拟机1.修改相关配置文件 四、虚拟机克隆及使用1.通用配置2.简单搭建一个java环境3.克隆虚拟机1.重命名虚拟机&#xff08;可选&#xff09;2.打包指定…

靶场练习 手把手教你通关DC系列 DC1

DC1靶场通关教程 文章目录 DC1靶场通关教程前言一、信息收集1.主机存活2.端口收集3.网页信息收集4.目录收集4.1 Nikto4.2 Dirb 信息收集总结 二、漏洞发现与利用1. 发现2. 利用 三、FlagFlag1Flag2Flag3Flag4Flag5(提权) 前言 本次使用的kali机的IP地址为192.168.243.131 DC1的…

【2024_CUMCM】LINGO入门+动态规划

目录 什么是动态规划 怎么使用动态规划&#xff1f; 例题&#xff1a;最短路线问题 2020b-问题一 稳定性分析 灵敏度分析 什么是动态规划 基本想法&#xff1a;将原问题转换为一系列相互联系的子问题&#xff0c;然后通过逐层递推求得最后的解 基本思想&#xff1a;解决…

X12端口配置指南:ISA ID、测试指示符与997

通过知行之桥EDI系统实现X12 & 标准XML之间的格式转换时&#xff0c;需要完善交换头ISA ID及其限定符、测试标识符以及997的相关配置。 在X12文件中有两组EDI ID对&#xff0c;分别是发送方 ID 限定符 及发送方ID &#xff0c;接收方 ID 限定符及接收方ID。 比如&#xf…

STM32Cubemx配置生成 Keil AC6支持代码

文章目录 一、前言二、AC 6配置2.1 ARM ComPiler 选择AC62.2 AC6 UTF-8的编译命令会报错 三、STM32Cubemx 配置3.1 找到stm32cubemx的模板位置3.2 替换文件内核文件3.3 修改 cmsis_os.c文件3.4 修改本地 四、编译对比 一、前言 使用keil ARM compiler V5的时候&#xff0c;编译…

Java内存区域与内存溢出异常(自动内存管理)

序言&#xff1a;Java与C之间有一堵由内存动态分配和垃圾收集技术所围成的高墙&#xff0c;墙外面的人想进去&#xff0c;墙里面的人却想出来。 1.1概述 对于从事C、C程序开发的开发人员来说&#xff0c;在内存管理领域&#xff0c;他们既是拥有最高权力的“皇帝”&#xff0c…

在FPGA程序中Handshake(握手)和Register(寄存器)区别

在FPGA程序中&#xff0c;Handshake&#xff08;握手&#xff09;和Register&#xff08;寄存器&#xff09;是两种不同的通信和数据传输机制。它们各有特点和适用场景。以下是它们的区别和应用场景的详细解释&#xff1a; Register&#xff08;寄存器&#xff09; 特点&#…

SQLServer用户们,你们摊上大事了!

最近一段时间&#xff0c;我们经常会收到了许多用户的咨询&#xff0c;问我们何时能纳管SQLServer&#xff1f;耐不住小伙伴们的猛烈催促及热切期待&#xff0c;本不想纳管SQLServer的研发团队也抓紧将这项需求提上日程。并在DBdoctor v3.2.2版本中成功实现了对SQLServer的纳管…

班级录取查询系统如何制作

在教育的长河中&#xff0c;我们每位老师都曾面临过这样一个问题&#xff1a;如何高效、准确地完成班级录取查询的任务&#xff1f;记得在以往&#xff0c;每当新学期伊始&#xff0c;我们不得不手忙脚乱地整理学生名单&#xff0c;然后逐一通知他们所在的班级。这个过程不仅耗…

《mysql篇》--索引事务

索引 索引的介绍 索引是帮助MySQL高效获取数据的数据结构&#xff0c;是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针&#xff0c;因为索引本身也比较大&#xff0c;所以索引一般是存储在磁盘上的&#xff0c;索引的种类有很多&#xff0c;不过如果没有特殊…

[ios-h5]在ios系统浏览器中输入框得到焦点时页面自动放大

问题&#xff1a; 在ios系统浏览器中输入框得到焦点时页面自动放大。 解决&#xff1a; 添加meta标签。 <meta name"apple-mobile-web-app-capable" content"yes" /> <meta name"viewport" content"widthdevice-width, initial-…

隐式类型转换 算术转换

目录 整型提升 间接证明整型提升的代码案例 算术转换 整型提升 何为整型提升&#xff1a; C语言的整型算术运算总是至少以缺省&#xff08;默认&#xff09;整型类型的精度来进行的 为了获得这个精度&#xff0c;表达式中的字符类型和短整型操作数在使用之前被转换为普通整…

基于SpringBoot实现轻量级的动态定时任务调度

在使用SpringBoot框架进行开发时&#xff0c;一般都是通过Scheduled注解进行定时任务的开发&#xff1a; Component public class TestTask {Scheduled(cron"0/5 * * * * ? ") //每5秒执行一次public void execute(){SimpleDateFormat df new SimpleDateFormat(…

解决 NullReferenceException: Object reference not set to an instance of an object

在 Unity 中 利用 URDF Importer import UR5e_gripper 的 URDF file 时出现错误&#xff1a; NullReferenceException: Object reference not set to an instance of an object。 理论上是有个Object 是 Null&#xff0c;当我再次检查URDF后仍觉得路径没有写错。 于是我 把Mesh…

软件测试面试200问(含答案+文档)

Part1 1、你的测试职业发展是什么&#xff1f; 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自…