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.mzph.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;⽣成反序列化利⽤数据&…

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

给个关注&#xff1f;宝儿&#xff01; 给个关注&#xff1f;宝儿&#xff01; 给个关注&#xff1f;宝儿&#xff01; 目录图解代码demo涉及的接口与类&#xff1a;TransformedMapTransformerConstantTransformerInvokerTransformerChainedTransformerdome理解总结&#xff1a…

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;请先阅读本节。 逻辑架构组件部分描述了逻辑组件。后面的部…

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;要知道只有中序前/后序可以唯一确定一棵二叉树&…

目标检测综述

目标检测综述 转自&#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…

视频质量评价:挑战与机遇

视频质量评价&#xff1a;挑战与机遇 转自&#xff1a;https://zhuanlan.zhihu.com/p/384603663 本文整理自鹏城实验室助理研究员王海强在LiveVideoStack线上分享上的演讲。他通过自身的实践经验&#xff0c;详细讲解了视频质量评价的挑战与机遇。 文 / 王海强 整理 / LiveVi…

关于二分法的边界问题及两种写法

关于二分法的边界问题及两种写法 二分查找法大家很熟悉了&#xff0c;对于一个有序序列&#xff0c;我们可以通过二分查找法在 O(logN)O(logN)O(logN) 的时间内找到想要的元素。但是&#xff0c;在代码实现的过程中&#xff0c;如果没有仔细理解清楚&#xff0c;二分法的边界条…

Segmentaion标签的三种表示:poly、mask、rle

Segmentaion标签的三种表示&#xff1a;poly、mask、rle 不同于图像分类这样比较简单直接的计算机视觉任务&#xff0c;图像分割任务&#xff08;又分为语义分割、实例分割、全景分割&#xff09;的标签形式稍为复杂。在分割任务中&#xff0c;我们需要在像素级上表达的是一张…

Ubuntu PPA 使用指南

Ubuntu PPA 使用指南 转自&#xff1a;https://zhuanlan.zhihu.com/p/55250294 一篇涵盖了在 Ubuntu 和其他 Linux 发行版中使用 PPA 的几乎所有问题的深入的文章。 如果你一直在使用 Ubuntu 或基于 Ubuntu 的其他 Linux 发行版&#xff0c;例如 Linux Mint、Linux Lite、Zorin…

杨宏宇:腾讯多模态内容理解技术及应用

杨宏宇&#xff1a;腾讯多模态内容理解技术及应用 分享嘉宾&#xff1a;杨宇鸿 腾讯 内容理解高级工程师 编辑整理&#xff1a;吴祺尧 出品平台&#xff1a;DataFunTalk 导读&#xff1a; 搜索内容的理解贯穿了整个搜索系统。我们需要从多个粒度理解搜索内容&#xff0c;包括语…

CUDA环境详解

CUDA环境详解 本文主要介绍 CUDA 环境&#xff0c;这一堆东西网上有很多博客介绍过了&#xff0c;我再来一篇:)&#xff0c;参考前辈们的文章&#xff0c;看能不能写的更清楚一点。读后仍有问题&#xff0c;欢迎留言交流。 CUDA APIs CUDA是由NVIDIA推出的通用并行计算架构&…