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.pswp.cn/diannao/43673.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/43673.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/43673.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java入門-Day7-面對對象基礎-構造器

&#xff08;1&#xff09;特點 創建對象時&#xff0c;對象會去調用構造器 &#xff08;2&#xff09;應用場景 創建對象時&#xff0c;同時完成對對象的成員變量&#xff08;屬性&#xff09;&#xff0c;的初始化 &#xff08;3&#xff09;注意事項 //Sutdent構造器 注…

Java 幼兒園(20240709)多來源列表映射多實現類

1、功能場景 對接多個外部廠商&#xff0c;比如多個銀行的賬單獲取&#xff0c;需要根據銀行信息執行對應的實現類。 2、功能代碼 &#xff08;1&#xff09;YAML配置來源列表 bank-source: bank_001, bank_002, bank_003 &#xff08;2&#xff09;外部來源枚舉 public …

《夢醒蝶飛:釋放Excel函數與公式的力量》10.2 COMPLEX函數

第二節 10.2 COMPLEX函數 10.2.1函數簡介 COMPLEX函數是Excel中的一個工程函數&#xff0c;用于將實部和虛部組合成一個復數。復數廣泛應用于工程、電氣、物理等領域&#xff0c;COMPLEX函數提供了方便的復數表示和計算方法。 10.2.2語法&#xff1a; COMPLEX(real_num, i_…

flex 填滿剩余空間

常見的flex屬性值&#xff1a; 1.flex:1,也就是flex-grow:1,也就是上面說的自動放大填充滿剩余空間&#xff0c;若有其他子盒子設置flex&#xff0c;則平分。 2.flex:0 0 auto,等同于flex:none,子元素的長度決定它的長度&#xff0c;當整體空間不足時&#xff0c;它也不會縮小&…

swift獲取app網絡和本地網絡權限

請求藍牙權限&#xff1a; //藍牙if #available(iOS 13.1, *) {let autostate CBManager.authorizationif(autostate .notDetermined){print("")self.manager CBCentralManager(delegate: nil, queue: DispatchQueue.main,options: [CBCentralManagerOptionShowPo…

JavaScript中的LHS和RHS

LHS和RHS之前我們先來回憶一下最簡單的賦值操作! var test100; console.log(test); 以上代碼的意思簡單我們理解為把右邊的值賦值給左邊的test變量,然后輸出打印結果。 可是我們要是深入理解你就會發現在這個過程當中&#xff0c;還發生了一些其他的事情 而這些事情就是今天…

C語言 printf函數緩沖機制

printf不立即打印到stdout的原因 printf函數使用了緩沖機制。當我們調用printf時,輸出通常不會立即顯示在屏幕上,而是先存儲在一個緩沖區中。這是為了提高I/O操作的效率。 緩存數據輸出的原理 stdio庫維護了一個緩沖區。當緩沖區滿了,或者在特定條件下,緩沖區的內容會被刷新…

前端如何讓網頁頁面完美適配不同大小和分辨率屏幕

推薦使用postcss插件&#xff0c;它會自動將項目所有的px單位統一轉換為vw等單位&#xff08;包括npm安裝的第三方組件&#xff09;&#xff0c;從而實現適配&#xff0c;具體配置規則可參考官網或npm網站介紹。 另外對于大屏的適配&#xff0c;需要縮放網頁&#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的…

機器學習 - 比較檢驗

列聯表 列聯表&#xff08;Contingency Table&#xff09;是一種用于顯示兩個或多個分類變量之間關系的表格。它廣泛應用于統計學中的分類數據分析&#xff0c;尤其在獨立性檢驗和關聯性分析時。列聯表的每個單元格展示了相應分類變量組合的頻數&#xff08;或比例&#xff09…

【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;編譯…

RK3568 buildroot 使用dropbear實現ssh遠程的方法

RK3568 buildroot 使用dropbear實現ssh遠程的方法 文章目錄 RK3568 buildroot 使用dropbear實現ssh遠程的方法前言一、創建S99dropbear.sh腳本二、創建sshd_config三、添加root賬戶密碼到系統驗證登錄前言 rk3568 linux 的sdk中,buildroot已經集成了dropbear的所需的lib庫環境…

交替打印-GO

1 兩個channel 版本 package mainimport ("fmt""sync")var wg sync.WaitGroup var c1 chan int var c2 chan intfunc A(){defer wg.Done()for i:0;i<10;i {<-c1fmt.Println(2*i)c2<-1 //牽引協程} } func B(){defer wg.Done()for i:0…

Java內存區域與內存溢出異常(自動內存管理)

序言&#xff1a;Java與C之間有一堵由內存動態分配和垃圾收集技術所圍成的高墻&#xff0c;墻外面的人想進去&#xff0c;墻里面的人卻想出來。 1.1概述 對于從事C、C程序開發的開發人員來說&#xff0c;在內存管理領域&#xff0c;他們既是擁有最高權力的“皇帝”&#xff0c…

使用OpenCV在按下Enter鍵時截圖并保存到指定文件夾

使用OpenCV在按下Enter鍵時截圖并保存到指定文件夾 在這篇博客中&#xff0c;我們將介紹如何使用OpenCV庫來實現一個簡單的功能&#xff1a;在按下Enter鍵時從攝像頭截圖并保存到指定的文件夾中。這個功能可以用于各種應用&#xff0c;例如監控系統、視頻捕捉等。 前置條件 …