title: javasec(四)序列化与反序列化基本原理
tags:
- javasec
- 反序列化
categories:
- javasec
cover: 'https://blog-1313934826.cos.ap-chengdu.myqcloud.com/blog-images/1.jpeg'
feature: false
date: 2023-04-18 16:02:20

这篇文章介绍java序列化与反序列化基本原理。

序列化与反序列化

Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。

Java的反序列化和PHP的反序列化其实有点类似,他们都只能将一个对象中的属性按照某种特定的格式生成一段数据流,在反序列化的时候再按照这个格式将属性拿回来,再赋值给新的对象。

但Java相对PHP序列化更深入的地方在于,其提供了更加高级、灵活地方法writeObject,允许开发者在序列化流中插入一些自定义数据,进而在反序列化的时候能够使用readObject进行读取。当然,PHP中也提供了一个魔术方法叫__wakeup,在反序列化的时候进行触发。

很多人会认为Java的readObject和PHP的__wakeup类似,但其实不全对,虽然都是在反序列化的时候触发,但他们解决的问题稍微有些差异。Java设计readObject的思路和PHP的__wakeup不同点于:readObject倾向于解决“反序列化时如何还原一个完整对象”这个问题,而PHP的__wakeup更倾向于解决“反序列化后如何初始化这个对象”的问题。

序列化实现

只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常)

Serializable 接口

public interface Serializable {
}

Serializable 用来标识当前类可以被 ObjectOutputStream 序列化,以及被 ObjectInputStream 反序列化。

Serializable 接口的基本使用

通过 ObjectOutputStream 将需要序列化数据写入到流中,因为 Java IO 是一种装饰者模式,因此可以通过 ObjectOutStream 包装 FileOutStream 将数据写入到文件中或者包装 ByteArrayOutStream 将数据写入到内存中。同理,可以通过 ObjectInputStream 将数据从磁盘 FileInputStream 或者内存 ByteArrayInputStream 读取出来然后转化为指定的对象即可。

代码实现

定义一个Person类进行测试。

import java.io.Serializable;

public class Person implements Serializable {
public String name;
public int age; Person(String name, int age) {
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

测试类

把序列化和反序列化写在一个文件进行测试。

package test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; public class SerializableTest {
public static void main(String[] args) throws Exception {
Serialize();
Unserialize();
} private static void Serialize() throws Exception{
Person p1 = new Person("Uf9n1x",22);
System.out.println("序列化前"+"\r\n"+p1.toString());
System.out.println("=================开始序列化================");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("\\......\\Test\\b"));
oos.writeObject(p1);
oos.flush();
oos.close();
} private static void Unserialize() throws Exception{
System.out.println("=================开始反序列化================");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("\\.......\\Test\\b"));
Person p2 = (Person) ois.readObject();
ois.close();
System.out.println("反序列化后:");
System.out.println(p2); } }

ObjectOutputStream代表对象输出流:它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中

ObjectInputStream代表对象输入流:它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

很显然,writeObject和readObject是序列化和反序列化的关键。

使用SerializationDumper查看序列化文件:

java -jar SerializationDumper.jar -r "\D:\..........\Test\b"
STREAM_MAGIC - 0xac ed
STREAM_VERSION - 0x00 05
Contents
TC_OBJECT - 0x73
TC_CLASSDESC - 0x72
className
Length - 11 - 0x00 0b
Value - test.Person - 0x746573742e506572736f6e
serialVersionUID - 0x6f 32 59 11 fb f8 d0 75
newHandle 0x00 7e 00 00
classDescFlags - 0x02 - SC_SERIALIZABLE
fieldCount - 2 - 0x00 02
Fields
0:
Int - I - 0x49
fieldName
Length - 3 - 0x00 03
Value - age - 0x616765
1:
Object - L - 0x4c
fieldName
Length - 4 - 0x00 04
Value - name - 0x6e616d65
className1
TC_STRING - 0x74
newHandle 0x00 7e 00 01
Length - 18 - 0x00 12
Value - Ljava/lang/String; - 0x4c6a6176612f6c616e672f537472696e673b
classAnnotations
TC_ENDBLOCKDATA - 0x78
superClassDesc
TC_NULL - 0x70
newHandle 0x00 7e 00 02
classdata
test.Person
values
age
(int)22 - 0x00 00 00 16
name
(object)
TC_STRING - 0x74
newHandle 0x00 7e 00 03
Length - 6 - 0x00 06
Value - Uf9n1x - 0x5566396e3178

可以看到,classdata存储类的相关数据,序列化重新取出使用。

安全问题

为什么会产生安全问题?

只要服务端反序列化数据,客户端传递类的readObject中的代码会自动执行,给予攻击者在服务器上运行代码的能力。

传递类产生漏洞的形式:

1)入口类的reaadObject直接调用危险方法。

Person类加入readObject重写方法,reaadObject(反序列化)调用命令执行方法。

import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.Serializable; public class Person implements Serializable {
public String name;
public int age; Person(String name, int age) {
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
} private void readObject(ObjectInputStream ois) throws Exception{
ois.defaultReadObject(); //该方法从该流中读取当前类的非静态和非瞬态字段。
Runtime.getRuntime().exec("calc");
System.out.println("命令执行成功!");
} }

2)入口类参数中包含可控类,这个类有危险方法,readObject时调用。

​ 入口A HashMap接收参数O (O.func) ->目标类B URL->目标类调用B.func->A.readObject.invoke->B.func==== URLDNS

3)入口类参数中包含可控类,该类又调用其他有危险的类,readObject时调用。

​ 目标类B.func

​ 入口A[O]->O.abc->B.func

​ O[B] invoke->B.func

​ O 是动态代理

4)构造函数/静态代码块等类加载时隐式执行。

上面的4个类别,入口类 Source 的共同的特征是:

  • 实现Serializable;
  • 重写readObject方法,调用一个常见的函数;
  • 参数类型宽泛;
  • 最好JDK自带;

小结

  1. Java类只有实现Serializable接口或Externalizable接口才可启用序列化功能;
  2. 当一个对象被序列化时,只保存对象的非静态成员变量;
  3. 如果一个对象发成员变量是一个对象,那么这个对象的数据成员也会被序列化;
  4. 使用transient关键字声明不需要被序列化的变量;(private transient String sex)
  5. 如果父类实现序列化,那么子类就自动实现序列化,不需要再显式实现Serializable接口;
  6. 显式定义serialVersionUID。

javasec(四)序列化与反序列化基本原理的更多相关文章

  1. 老王讲自制RPC框架.(四.序列化与反序列化)

    #(序列化) 在实际的框架中,真正影响效率的就是数据的传输方式,以及传输的准备,或者说是tcp与http,序列化.当然要想提高整个框架的效率,需要采用一种高效的序列化 框架比如流行的protostuf ...

  2. 细说C#中的序列化与反序列化的基本原理和过程

    虽然我们平时都使用第三方库来进行序列化和反序列化,用起来也很方便,但至少得明白序列化与反序列化的基本原理. 懂得人就别看了! 注意:从.NET Framework 2.0 开始,序列化格式化器类Soa ...

  3. [.net 面向对象程序设计进阶] (12) 序列化(Serialization)(四) 快速掌握JSON的序列化和反序列化

    [.net 面向对象程序设计进阶] (12) 序列化(Serialization)(四) 快速掌握JSON的序列化和反序列化 本节导读: 介绍JSON的结构,在JS中的使用.重点说明JSON如何在.N ...

  4. 【原】iOS动态性(四):一行代码实现iOS序列化与反序列化(runtime)

    为取得更好的排版效果,本文同样发布在简书上,强烈建议跳转到[1]http://www.jianshu.com/p/fed1dcb1ac9f 一.变量声明 为便于下文讨论,提前创建父类Biology以及 ...

  5. 第四节:IO、序列化和反序列化、加密解密技术

    一. IO读写 这里主要包括文件的读.写.移动.复制.删除.文件夹的创建.文件夹的删除等常规操作. 注意:这里需要特别注意,对于普通的控制台程序和Web程序,将"相对路径"转换成& ...

  6. Java基础IO流(四)序列化与反序列化

    对象的序列化与反序列化: 对象的序列化,就是将Object转换成byte序列,反之叫对象的反序列化. 序列化流(ObjectOutInputStream),是过滤流 -------writeObjec ...

  7. Java基础知识➣序列化与反序列化(四)

    概述 Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据.有关对象的类型的信息和存储在对象中数据的类型. 将序列化对象写入文件之后,可以从文件 ...

  8. python第四十九课——对象序列化与反序列化

    person.py class Person: def __init__(self,*args,**kwargs): print('我是Person类的构造...') # self.name=name ...

  9. python接口测试之序列化与反序列化(四)

    在python中,序列化可以理解为:把python的对象编码转换为json格式的字符串,反序列化可以理解为:把json格式 字符串解码为python数据对象.在python的标准库中,专门提供了jso ...

  10. 对象的序列化与反序列化---IO学习笔记(四)

    对象的序列化,反序列化 对象的序列化: 就是将Object转换成byte序列 对象的反序列化: 将byte序列转换成Object 序列化流.反序列化流 序列化流(ObjectOutputStream) ...

随机推荐

  1. C++11的override、default和delete关键字

    最近在参与组里的项目时接触了很多以前自己没太了解的C++语法(尤其是C++11以后出现的),今天给大家讲一下C++11新出的override和default关键字. override关键字主要在声明类 ...

  2. 贪心算法(Java)

    贪心算法 文章目录 贪心算法 0.写在前面 1.贪心算法的基本要素 1.1 贪心选择性质 1.2 最优子结构性质 1.3 贪心算法与动态规划算法的差异 2.贪心算法的特点 3.贪心法的正确性证明 4. ...

  3. Linux 复制时排除某文件/目录

    如果要排除/home/data目录下面的a.b.c.三个目录,同时拷贝其它所有目录,执行rsync命令yum install rsync -y #安装rsync 排除单个文件/目录rsync -avP ...

  4. Hive使用Tez作为计算引擎,hive启动报错

    1.问题描述: (1)问题示例: 1)hive使用配置文件hive-site.xml配置tez为计算引擎,hive登录报错: [Hadoop@master Tmp]$ hiveHive Session ...

  5. sql server 索引检测

    -- 声明表变量 DECLARE @userTable TABLE (table_name NVARCHAR(20)); -- 将源表中的数据插入到表变量中 INSERT INTO @userTabl ...

  6. 自定义DOM事件函数封装

    非原生DOM触发,个性化定制的自定义事件. currentTarget(DOM对象):要触发事件的元素节点. type(字符串):触发的事件类型,例如"keydown". bubb ...

  7. 使用yarn启用项目,报错无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\yarn.ps1,因为在此系 统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。

    这是由于新版win10 安装的时候会出现: 解决 搜索powershell,右键以管理员身份运行 2.打开之后,执行命令set-ExecutionPolicy RemoteSigned更改 Power ...

  8. 在教学中常被问到的几个vue3.x与typescript的问题,统一解答

    在教学当中,学生在学习vue3.x时,常常会问到typescript和vue3.x之间的关系,感觉这两个技术总是绑在一起的,下面老赵来统一解答一下: 那学vue3.x,为什么要求也要掌握typescr ...

  9. 【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序

    logo 避坑宝 v1.0.0 基于SpringBoot+uniapp企业黑红名单吐槽小程序 项目介绍 避坑宝 [避坑宝]企业黑红名单吐槽小程序是一个具有吐槽发布企业信息的一个平台,言论自由,评判自定 ...

  10. 如何使用Mutex确保并发程序的正确性

    1. 简介 本文的主要内容是介绍Go中Mutex并发原语.包含Mutex的基本使用,使用的注意事项以及一些实践建议. 2. 基本使用 2.1 基本定义 Mutex是Go语言中的一种同步原语,全称为Mu ...