java安全(五)java反序列化

給個關注?寶兒!
給個關注?寶兒!
給個關注?寶兒!

在這里插入圖片描述

1. 序列化

在調用RMI時,發現接收發送數據都是反序列化數據.

例如JSON和XML等語言,在網絡上傳遞信息,都會用到一些格式化數據,大多數處理方法中,JSON和XML支持的數據類型就是基本數據類型,整型、浮點型、字符串、布爾等,如果開發者希望在傳輸數據的時候直接傳輸一個對象,那么就不得不想辦法擴展基礎的JSON(XML)語法。比如,Jackson和Fastjson這類序列化庫,在JSON(XML)的基礎上進行改造,通過特定的語法來傳遞對象.

RMI使用java等語言內置的序列化方法,將一個對象轉化成一串二進制數據進行傳輸

2.反序列化

不管是Jackson、Fastjson還是編程語言內置的序列化方法,一旦涉及到序列化與反序列化數據,就可能會涉及到安全問題。但首先要理解的是,“反序列化漏洞”是對一類漏洞的泛指,而不是專指某種反序列化方法導致的漏洞,比如Jackson反序列化漏洞和Java readObject造成的反序列化漏洞就是完全不同的兩種漏洞。

在Java中實現對象反序列化非常簡單,實現java.io.Serializable(內部序列化)java.io.Externalizable(外部序列化)接口即可被序列化,其中java.io.Externalizable接口只是實現了java.io.Serializable接口。

反序列化類對象時有如下限制:
1.被反序列化的類必須存在。
2. serialVersionUID值必須一致。

除此之外,反序列化類對象是不會調用該類構造方法的,因為在反序列化創建類實例時使用了sun.reflect.ReflectionFactory.newConstructorForSerialization創建了一個反序列化專用的Constructor(反射構造方法對象),使用這個特殊的Constructor可以繞過構造方法創建類實例(前面章節講sun.misc.Unsafe 的時候我們提到了使用allocateInstance方法也可以實現繞過構造方法創建類實例)。

3.反序列化方法的對比

在接觸Java反序列化之前,相比大家多少都了解過其他語言的反序列化漏洞,其中極為經典的要數PHP
和Python。
那么,Java的反序列化,究竟和PHP、Python的反序列化有什么異同?
Java的反序列化和PHP的反序列化其實有點類似,他們都只能將一個對象中的屬性按照某種特定的格式
生成一段數據流,在反序列化的時候再按照這個格式將屬性拿回來,再賦值給新的對象。
但Java相對PHP序列化更深入的地方在于,其提供了更加高級、靈活地方法 writeObject ,允許開發者
在序列化流中插入一些自定義數據,進而在反序列化的時候能夠使用 readObject 進行讀取。
當然,PHP中也提供了一個魔術方法叫 __wakeup ,在反序列化的時候進行觸發。很多人會認為Java的 readObject 和PHP的 __wakeup 類似,但其實不全對,雖然都是在反序列化的時候觸發,但他們解決
的問題稍微有些差異。
Java設計 readObject 的思路和PHP的 __wakeup 不同點在于:
readObject 傾向于解決“反序列化時如
何還原一個完整對象”這個問題,而PHP的 __wakeup 更傾向于解決“反序列化后如何初始化這個對象”的
問題。

4.PHP反序列化

PHP的序列化是開發者不能參與的,開發者調用 serialize 函數后,序列化的數據就已經完成了,你得到的是一個完整的對象,你并不能在序列化數據流里新增某一個內容,你如果想插入新的內容,只有將其保存在一個屬性中。也就是說PHP的序列化、反序列化是一個純內部的過程,而其 __sleep 、 __wakeup 魔術方法的目的就是在序列化、反序列化的前后執行一些操作。

一個非常典型的PHP序列化例子,就是含有資源類型的PHP類,如數據庫連接:

<?php 
class Connection 
{ 
protected $link; 
private $dsn, $username, $password; 
public function __construct($dsn, $username, $password) 
{ 
$this->dsn = $dsn; 
$this->username = $username; 
$this->password = $password; 
$this->connect(); 
}
private function connect() 
{ 
$this->link = new PDO($this->dsn, $this->username, $this- 
>password); 
} 
} 

PHP中,資源類型的對象默認是不會寫入序列化數據中的。那么上述Connection類的 $link 屬性在序
列化后就是null,反序列化時拿到的也是null。
那么,如果我想要反序列化時拿到的 $link 就是一個數據庫連接,我就需要編寫 __wakeup 方法:

<?php 
class Connection 
{ 
protected $link; 
private $dsn, $username, $password; 
public function __construct($dsn, $username, $password) 
{ 
$this->dsn = $dsn; 
$this->username = $username; 
$this->password = $password; 
$this->connect(); 
}
private function connect() 
{ 
$this->link = new PDO($this->dsn, $this->username, $this- 
>password); 
}
public function __sleep() 
{ 
return array('dsn', 'username', 'password'); 
}
public function __wakeup() 
{ 
$this->connect(); 
} 

可見,這里 __wakeup 的工作就是在反序列化拿到Connection對象后,執行 connect() 函數,連接數
據庫。
__wakeup 的作用在反序列化后,執行一些初始化操作。但其實我們很少利用序列化數據傳遞資源類型
的對象,而其他類型的對象,在反序列化的時候就已經賦予其值了。
所以你會發現,PHP的反序列化漏洞,很少是由 __wakeup 這個方法觸發的,通常觸發在析構函數
__destruct 里。其實大部分PHP反序列化漏洞,都并不是由反序列化導致的,只是通過反序列化可以
控制對象的屬性,進而在后續的代碼中進行危險操作。

5.Java反序列化

在Java中實現對象反序列化非常簡單,實現java.io.Serializable(內部序列化)java.io.Externalizable(外部序列化)接口即可被序列化,其中java.io.Externalizable接口只是實現了java.io.Serializable接口。

反序列化類對象時有如下限制:
1.被反序列化的類必須存在。
2. serialVersionUID值必須一致。

除此之外,反序列化類對象是不會調用該類構造方法的,因為在反序列化創建類實例時使用了sun.reflect.ReflectionFactory.newConstructorForSerialization創建了一個反序列化專用的Constructor(反射構造方法對象),使用這個特殊的Constructor可以繞過構造方法創建類實例(前面章節講sun.misc.Unsafe 的時候我們提到了使用allocateInstance方法也可以實現繞過構造方法創建類實例)。

使用反序列化方式創建類實例代碼片段:

package com.anbai.sec.serializes;import sun.reflect.ReflectionFactory;import java.lang.reflect.Constructor;/*** 使用反序列化方式在不調用類構造方法的情況下創建類實例* https://www.iteye.com/topic/850027*/
public class ReflectionFactoryTest {public static void main(String[] args) {try {// 獲取sun.reflect.ReflectionFactory對象ReflectionFactory factory = ReflectionFactory.getReflectionFactory();// 使用反序列化方式獲取DeserializationTest類的構造方法Constructor constructor = factory.newConstructorForSerialization(DeserializationTest.class, Object.class.getConstructor());// 實例化DeserializationTest對象System.out.println(constructor.newInstance());} catch (Exception e) {e.printStackTrace();}}}

輸出
在這里插入圖片描述

6.ObjectInputStream、ObjectOutputStream

java.io.ObjectOutputStream類最核心的方法是writeObject方法,即序列化類對象。

java.io.ObjectInputStream類最核心的功能是readObject方法,即反序列化類對象。

所以,只需借助ObjectInputStream和ObjectOutputStream類我們就可以實現類的序列化和反序列化功能了。

7.java.io.Serializable

java.io.Serializable是一個空的接口,我們不需要實現java.io.Serializable的任何方法,代碼如下:

public interface Serializable {
}

您可能會好奇我們實現一個空接口有什么意義?其實實現java.io.Serializable接口僅僅只用于標識這個類可序列化。實現了java.io.Serializable接口的類原則上都需要生產一個serialVersionUID常量,反序列化時如果雙方的serialVersionUID不一致會導致InvalidClassException 異常。如果可序列化類未顯式聲明 serialVersionUID,則序列化運行時將基于該類的各個方面計算該類的默認 serialVersionUID值。

DeserializationTest.java測試代碼如下:

package com.anbai.sec.serializes;import java.io.*;
import java.util.Arrays;/*** Creator: yz* Date: 2019/12/15*/
public class DeserializationTest implements Serializable {private String username;private String email;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public static void main(String[] args) {ByteArrayOutputStream baos = new ByteArrayOutputStream();try {// 創建DeserializationTest類,并類設置屬性值DeserializationTest t = new DeserializationTest();t.setUsername("yz");t.setEmail("admin@.com");// 創建Java對象序列化輸出流對象ObjectOutputStream out = new ObjectOutputStream(baos);// 序列化DeserializationTest類out.writeObject(t);out.flush();out.close();// 打印DeserializationTest類序列化以后的字節數組,我們可以將其存儲到文件中或者通過Socket發送到遠程服務地址System.out.println("DeserializationTest類序列化后的字節數組:" + Arrays.toString(baos.toByteArray()));// 利用DeserializationTest類生成的二進制數組創建二進制輸入流對象用于反序列化操作ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());// 通過反序列化輸入流(bais),創建Java對象輸入流(ObjectInputStream)對象ObjectInputStream in = new ObjectInputStream(bais);// 反序列化輸入流數據為DeserializationTest對象DeserializationTest test = (DeserializationTest) in.readObject();System.out.println("用戶名:" + test.getUsername() + ",郵箱:" + test.getEmail());// 關閉ObjectInputStream輸入流in.close();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}}

輸出:
在這里插入圖片描述
核心邏輯其實就是使用ObjectOutputStream類的writeObject方法序列化DeserializationTest類,使用ObjectInputStream類的readObject方法反序列化DeserializationTest類而已。

簡化后的代碼片段如下:

// 序列化DeserializationTest類
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(t);// 反序列化輸入流數據為DeserializationTest對象
ObjectInputStream in = new ObjectInputStream(bais);
DeserializationTest test = (DeserializationTest) in.readObject();

ObjectOutputStream序列化類對象的主要流程是首先判斷序列化的類是否重寫了writeObject方法,如果重寫了就調用序列化對象自身的writeObject方法序列化,序列化時會先寫入類名信息,其次是寫入成員變量信息(通過反射獲取所有不包含被transient修飾的變量和值)。

8.java.io.Externalizable.java:

public interface Externalizable extends java.io.Serializable {void writeExternal(ObjectOutput out) throws IOException;void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;}

ExternalizableTest.java測試代碼如下:

package com.anbai.sec.serializes;import java.io.*;
import java.util.Arrays;/*** Creator: yz* Date: 2019/12/15*/
package com.anbai.sec.serializes;import java.io.*;
import java.util.Arrays;/*** Creator: yz* Date: 2019/12/15*/
public class ExternalizableTest implements java.io.Externalizable {private String username;private String email;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeObject(username);out.writeObject(email);}@Overridepublic void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {this.username = (String) in.readObject();this.email = (String) in.readObject();}public static void main(String[] args) {ByteArrayOutputStream baos = new ByteArrayOutputStream();try {// 創建ExternalizableTest類,并類設置屬性值ExternalizableTest t = new ExternalizableTest();t.setUsername("yz");t.setEmail("admin@javaweb.org");ObjectOutputStream out = new ObjectOutputStream(baos);out.writeObject(t);out.flush();out.close();// 打印ExternalizableTest類序列化以后的字節數組,我們可以將其存儲到文件中或者通過Socket發送到遠程服務地址System.out.println("ExternalizableTest類序列化后的字節數組:" + Arrays.toString(baos.toByteArray()));System.out.println("ExternalizableTest類反序列化后的字符串:" + new String(baos.toByteArray()));// 利用DeserializationTest類生成的二進制數組創建二進制輸入流對象用于反序列化操作ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());// 通過反序列化輸入流創建Java對象輸入流(ObjectInputStream)對象ObjectInputStream in = new ObjectInputStream(bais);// 反序列化輸入流數據為ExternalizableTest對象ExternalizableTest test = (ExternalizableTest) in.readObject();System.out.println("用戶名:" + test.getUsername() + ",郵箱:" + test.getEmail());// 關閉ObjectInputStream輸入流in.close();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}}

輸出:
在這里插入圖片描述
兩者之間沒有多大差別

9.自定義序列化(writeObject)和反序列化(readObject)

實現了java.io.Serializable接口的類,還可以定義如下方法(反序列化魔術方法),這些方法將會在類序列化或反序列化過程中調用:

  1. private void writeObject(ObjectOutputStream oos),自定義序列化。
  2. private void readObject(ObjectInputStream ois),自定義反序列化。
  3. private void readObjectNoData()。
  4. protected Object writeReplace(),寫入時替換對象。
  5. protected Object readResolve()。

具體的方法名定義在java.io.ObjectStreamClass#ObjectStreamClass(java.lang.Class<?>),其中方法有詳細的聲明。

序列化時可自定義的方法示例代碼:

public class DeserializationTest implements Serializable {/*** 自定義反序列化類對象** @param ois 反序列化輸入流對象* @throws IOException            IO異常* @throws ClassNotFoundException 類未找到異常*/private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {System.out.println("readObject...");// 調用ObjectInputStream默認反序列化方法ois.defaultReadObject();// 省去調用自定義反序列化邏輯...}/*** 自定義序列化類對象** @param oos 序列化輸出流對象* @throws IOException IO異常*/private void writeObject(ObjectOutputStream oos) throws IOException {oos.defaultWriteObject();System.out.println("writeObject...");// 省去調用自定義序列化邏輯...}private void readObjectNoData() {System.out.println("readObjectNoData...");}/*** 寫入時替換對象** @return 替換后的對象*/protected Object writeReplace() {System.out.println("writeReplace....");return null;}protected Object readResolve() {System.out.println("readResolve....");return null;}}

當我們對DeserializationTest類進行序列化操作時,會自動調用(反射調用)該類的writeObject(ObjectOutputStream oos)方法,對其進行反序列化操作時也會自動調用該類的readObject(ObjectInputStream)方法,也就是說我們可以通過在待序列化或反序列化的類中定義readObject和writeObject方法,來實現自定義的序列化和反序列化操作,當然前提是,被序列化的類必須有此方法,并且方法的修飾符必須是private。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532544.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532544.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532544.shtml

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

相關文章

git merge和rebase的區別與選擇

git merge和rebase的區別與選擇 轉自&#xff1a;https://github.com/geeeeeeeeek/git-recipes/wiki/5.1-%E4%BB%A3%E7%A0%81%E5%90%88%E5%B9%B6%EF%BC%9AMerge%E3%80%81Rebase-%E7%9A%84%E9%80%89%E6%8B%A9#merge BY 童仲毅&#xff08;geeeeeeeeekgithub&#xff09; 這是一篇…

java安全(六)java反序列化2,ysoserial調試

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; ysoserial 下載地址&#xff1a;https://github.com/angelwhu/ysoserial ysoserial可以讓?戶根據??選擇的利?鏈&#xff0c;?成反序列化利?數據&…

C++面試常見問題一

C面試常見問題一 轉自&#xff1a;https://oldpan.me/archives/c-interview-answer-1 原作者&#xff1a;[oldpan][https://oldpan.me/] 前言 這里收集市面上所有的關于算法和開發崗最容易遇到的關于C方面的問題&#xff0c;問題信息來自互聯網以及牛客網的C面試題目匯總。答題…

java安全(七) 反序列化3 CC利用鏈 TransformedMap版

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 目錄圖解代碼demo涉及的接口與類&#xff1a;TransformedMapTransformerConstantTransformerInvokerTransformerChainedTransformerdome理解總結&#xff1a…

C++編譯時多態和運行時多態

C編譯時多態和運行時多態 作者&#xff1a;melonstreet 出處&#xff1a;https://www.cnblogs.com/QG-whz/p/5132745.html 本文版權歸作者和博客園共有&#xff0c;歡迎轉載&#xff0c;但未經作者同意必須保留此段聲明&#xff0c;且在文章頁面明顯位置給出原文連接&#xff0…

java安全(八)TransformedMap構造POC

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 上一篇構造了一個了commons-collections的demo 【傳送門】 package test.org.vulhub.Ser;import org.apache.commons.collections.Transformer; import org…

Pytorch Tutorial 使用torch.autograd進行自動微分

Pytorch Tutorial 使用torch.autograd進行自動微分 本文翻譯自 PyTorch 官網教程。 原文&#xff1a;https://pytorch.org/tutorials/beginner/basics/autogradqs_tutorial.html#optional-reading-tensor-gradients-and-jacobian-products 在訓練神經網絡時&#xff0c;最常使用…

TVM:編譯深度學習模型快速上手教程

TVM&#xff1a;編譯深度學習模型快速上手教程 本文將展示如何使用 Relay python 前端構建一個神經網絡&#xff0c;并使用 TVM 為 Nvidia GPU 生成一個運行時庫。 注意我們需要再構建 TVM 時啟用了 cuda 和 llvm。 TVM支持的硬件后端總覽 在本教程中&#xff0c;我們使用 cu…

TVM:設計與架構

TVM&#xff1a;設計與架構 本文檔適用于想要了解 TVM 架構和/或積極開發項目的開發人員。頁面組織如下&#xff1a; 示例編譯流程概述了 TVM 將模型的高層描述轉換為可部署模塊所采取的步驟。要開始使用&#xff0c;請先閱讀本節。 邏輯架構組件部分描述了邏輯組件。后面的部…

遞歸+回溯

遞歸-回溯 本文參考自代碼隨想錄視頻&#xff1a; https://www.bilibili.com/video/BV1cy4y167mM https://www.bilibili.com/video/BV1ti4y1L7cv 遞歸回溯理論基礎 只要有遞歸&#xff0c;就會有回溯&#xff0c;遞歸函數的下面的部分通常就是回溯的邏輯。 回溯是純暴力的搜索…

Nvidia CUDA初級教程1 CPU體系架構綜述

Nvidia CUDA初級教程1 CPU體系架構綜述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p2 講師&#xff1a;周斌 本節內容&#xff1a;了解現代CPU的架構和性能優化&#xff1a; 流水線 Pipelining分支預測 Branch Prediction超標量 Superscalar亂序執行 Out…

Nvidia CUDA初級教程2 并行程序設計概述

Nvidia CUDA初級教程2 并行程序設計概述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p3 講師&#xff1a;周斌 本節內容&#xff1a; 為什么需要&#xff1f;怎么做&#xff1f;一些技術和概念 串并行計算模式 串行計算模式 常規軟件時串行的 設計運行…

Nvidia CUDA初級教程4 GPU體系架構概述

Nvidia CUDA初級教程4 GPU體系架構概述 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p5 講師&#xff1a;周斌 本節內容&#xff1a; 為什么需要GPU三種方法提升GPU的處理速度實際GPU的設計舉例&#xff1a; NVDIA GTX 480: FermiNVDIA GTX 680: Kepler GP…

Nvidia CUDA初級教程5 CUDA/GPU編程模型

Nvidia CUDA初級教程5 CUDA/GPU編程模型 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p6 講師&#xff1a;周斌 本節內容&#xff1a; CPU和GPU互動模式GPU線程組織模型&#xff08;需要不停強化&#xff09;GPU存儲模型基本的編程問題 CPU與GPU交互 各自…

Nvidia CUDA初級教程6 CUDA編程一

Nvidia CUDA初級教程6 CUDA編程一 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p7 講師&#xff1a;周斌 GPU架構概覽 GPU特別使用于&#xff1a; 密集計算&#xff0c;高度可并行計算圖形學 晶體管主要被用于&#xff1a; 執行計算而不是 緩存數據控制指令…

由前中后遍歷序列構建二叉樹

由前/中/后遍歷序列構建二叉樹 基礎 首先&#xff0c;我們需要知道前中后序三種深度優先遍歷二叉樹的方式的具體順序&#xff1a; 前序&#xff1a;中左右中序&#xff1a;左中右后序&#xff1a;左右中 另外&#xff0c;要知道只有中序前/后序可以唯一確定一棵二叉樹&…

手寫nms

手寫nms 計算寬高的時候加1是為什么&#xff1f; 本文總結自互聯網的多種nms實現&#xff0c;供參考&#xff0c;非博主原創&#xff0c;各原文鏈接如下&#xff0c;也建議大家動手寫一寫。 Ref&#xff1a; 淺談NMS的多種實現 目標窗口檢測算法-NMS非極大值抑制 一、fas…

目標檢測綜述

目標檢測綜述 轉自&#xff1a;https://zhuanlan.zhihu.com/p/383616728 論文參考&#xff1a;[Object Detection in 20 Years: A Survey][https://arxiv.org/abs/1905.05055] 引言 目標檢測領域發展至今已有二十余載&#xff0c;從早期的傳統方法到如今的深度學習方法&#x…

Nvidia CUDA初級教程7 CUDA編程二

Nvidia CUDA初級教程7 CUDA編程二 視頻&#xff1a;https://www.bilibili.com/video/BV1kx411m7Fk?p8 講師&#xff1a;周斌 本節內容&#xff1a; 內置類型和函數 Built-ins and functions線程同步 Synchronizing線程調度 Scheduling threads存儲模型 Memory model重訪 Matr…

詳解優酷視頻質量評價體系

萬字長文 | 詳解優酷視頻質量評價體系 分享嘉賓&#xff5c;李靜博士&#xff0c;阿里巴巴文娛集團資深算法專家&#xff0c;阿里巴巴大文娛摩酷實驗室視頻體驗與質量團隊負責人 整理出品&#xff5c;AICUG人工智能社區 本文地址&#xff1a;https://www.6aiq.com/article/1617…