java序列化与反序列化详解

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

一:什么是反序列化

序列化:

序列化就是将 java对象 转化为字节序列的过程。
序列化是指把一个Java对象变成二进制内容,本质上就是一个byte[]数组。 为什么要把Java对象序列化呢?因为序列化后可以把byte[]保存到文件中,或者把byte[]通过网络传输到远程,这样,就相当于把Java对象存储到文件或者通过网络传输出去了。
注意:序列化是为了在传递和保存对象时,为了保证对象的完整性和可传递性。将对象转为有序的字节流,以便在网上传输或者保存在本地文件中。

反序列化:

反序列化就是将 字节序列恢复为java对象的过程。
有序列化,就有反序列化,即把一个二进制内容(也就是byte[]数组)变回Java对象。有了反序列化,保存到文件中的byte[]数组又可以“变回”Java对象,或者从网络上读取byte[]并把它“变回”Java对象。

二、序列化和反序列化的应用

两个进程在远程通信时,可以发送多种数据,包括文本、图片、音频、视频等,这些数据都是以二进制序列的形式在网络上传输。
java是面向对象的开发方式,一切都是java对象,想要在网络中传输java对象,可以使用序列化和反序列化去实现,发送发需要将java对象转换为字节序列,然后在网络上传送,接收方收到字符序列后,会通过反序列化将字节序列恢复成java对象。

三、序列化和反序列化地实现

1.JDK类库提供的序列化API:
java.io.ObjectOutputStream
表示对象输出流,其中writeObject(Object obj)方法可以将给定参数的obj对象进行序列化,将转换的一连串的字节序列写到指定的目标输出流中。
java.io.ObjectInputStream
该类表示对象输入流,该类下的readObject(Object obj)方法会从源输入流中读取字节序列,并将它反序列化为一个java对象并返回

序列化要求:

实现序列化的类对象必须实现了Serializable类或Externalizable类才能被序列化,否则会抛出异常

四、序列化和反序列化,遵循以下方法:

方法一:若student类实现了serializable接口,则可以通过objectOutputstream和objectinputstream默认的序列化和反序列化方式,对非transient的实例变量进行序列化和反序列化。

方法二:若student类实现了serializable接口,并且定义了writeObject(objectOutputStream out)和readObject(objectinputStream in)方法
则可以直接调用student类的两种方法进行序列化和反序列化

方法三:若student类实现了Externalizable接口,则必须实现readExternal(Objectinput in)和writeExternal(Objectoutput out)方法进行序列化和反序列化。

4.1 示例代码

package Serializa.Learn;

import java.io.*;

public class Person implements Serializable {

    private static String secret;
    private String name;


    private int age;

    transient private double saraly;

    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;
    }

    public double getSaraly() {
        return saraly;
    }

    public void setSaraly(double saraly) {
        this.saraly = saraly;
    }

    @Override
    public String toString() {
        return "Person{" +
            "name='" + name + '\'' +
            ", age='" + age + '\'' +
            ", saraly='" + saraly + '\'' +
            ", secret='" + secret + '\'' +
            '}';
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Person p1 = new Person();
        p1.setAge(18);
        p1.setName("lxl");
        p1.setSaraly(5000000);
        Person.secret = "aaa";
        System.out.println(p1);
        serizliza(p1);

        //        Person.secret="bbbb";
        Person p2 = (Person) deserizliza("person.ser");
        System.out.println("反序列化" + p2);

    }

    private static void serizliza(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"));
        oos.writeObject(obj);
    }

    private static Object deserizliza(String file) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        Object obj = ois.readObject();
        return obj;
    }
}

1.被transient 修饰的变量不会被序列化,同时若自定义了readObject方法,反序列化时则会执行 自定义的方法

image.png

2.不实现Serializable接口

image.png

3.让序列化的文件的serialVersionUID 和本地class 的不一致

1.首先定义serialVersionUID 然后按住 Ctrl + Shift + A 弹出的dialog 输入serialVersionUID 然后让java计算出独一无二的值

image.png

2.序列化person类,保存到本地,用SerializationDumper 查看序列化后的文件
java -jar SerializationDumper-v1.13.jar -r person.ser

image.png
serialVersionUID - 0x0e 76 fa 9f 59 73 be c6 是16进制转换为二进制,就是生成的值
image.png

3.使用010editor 修改serialVersionUID值

image.png
再次解析下修改后的数据,发现确实改变了
image.png
把序列化的代码注释,再次运行代码,执行反序列化,发现报错了
image.png
报错信息如下,确实符合 java 反序列的规范,

Exception in thread "main" java.io.InvalidClassException: Serializa.Learn.Person; local class incompatible: stream classdesc serialVersionUID = 1042295926090350279, local class serialVersionUID = 1042295926090350278
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2001)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1848)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2158)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1665)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:501)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:459)
    at Serializa.Learn.Person.deserizliza(Person.java:77)
    at Serializa.Learn.Person.main(Person.java:61)

所以这也就是为什么我们在利用反序列化漏洞的时候,明明有这个链,但是不能成功,因为版本不一致。所以serializaUID 不一致的原因,

PS:serialVersionUID 的初衷是为了在反序列化时确保类的版本号与序列化时的版本号一致,避免出现版本不一致的问题,serialVersionUID 是根据类的成员变量自动生成的。如果没有手动指定 serialVersionUID,Java会根据类的成员变量自动生成一个版本号

4. 反序列化文件的格式

原始的16进制格式

aced 0005

在这里插入图片描述

base64编码的

rO0ABXNyABZTZXJpYWxpemEuTGVhcm4uUGVyc29uey5vlQ4y/oYCAAJJAANhZ2VMAARuYW1ldAAS
TGphdmEvbGFuZy9TdHJpbmc7eHAAAAASdAAGUHl0aDBu
在这里插入图片描述

因此在平时我们渗透过程中如果在流量中看到aced0005开头 或rO0AB 开头的流量就需要注意了,很可能这里是存在反序列化的

4.2 注意事项

  1. 序列化类必须要实现Serializable接口
  2. 序列化类中对象属性要求实现Serializable接口
  3. serialVersionUID 序列化版本ID,保证序列化的类和反序列化的类是同一个类
  4. transient(瞬间的)修饰属性,这个属性就不能序列化了
  5. 静态属性也不能被序列化, 静态属性的值不会被序列化,因为它不属于任何一个对象,而是属于类
  6. 如果可以序列化,就会出现下面的情况,当我们序列化某个类的一个对象到某个文件后,这个文件中的对象的那个被static修饰的属性值会固定下来,当另外一个普通的的对象修改了该static属性后,我们再去反序列化那个文件中的对象,就会得到和后面的对象不同的static属性值,
  7. 用Java序列化的二进制字节数据只能由Java反序列化,不能被其他语言反序列化。如果要进行前后端或者不同语言之间的交互一般需要将对象转变成Json/Xml通用格式的数据,再恢复原来的对象。

4.3 transient真的不能被序列化么?

image.pngimage.png
执行结果
image.png
在 Java 中有两种实现序列化的方式,Serializable 和 Externalizable,可能大部分人只知道 Serializable 而不知道 Externalizable。
这两种序列化方式的区别是:实现了 Serializable 接口是自动序列化的,实现 Externalizable 则需要手动序列化,通过 writeExternal 和 readExternal 方法手动进行,
因为我只手动序列化了 saraly属性,所以其他值为初始化值

4.4 transient 关键字总结

  1. transient修饰的变量不能被序列化;
  2. transient只作用于实现 Serializable 接口;
  3. transient只能用来修饰普通成员变量字段;
  4. 不管有没有 transient 修饰,静态变量都不能被序列化;

五、参考资料

Java中的序列化反序列化 序列化(Serialization)反序列化(Deserialization)是编程中常见的两个概念,它们主要涉及到将数据结构或对象状态转换为可以存储或传输的格式,以及将存储或传输的格式转换回原始的数据结构或对象状态的过程。这两个过程在数据持久化、网络通信、对象深拷贝等多个场景中发挥着重要作用。 阅读详情

相关推荐

java安全(五)java反序列化

序列化 在调用RMI时,发现接收发送数据都是反序列化数据. 例如JSONXML等语言,在网络上传递信息,都会用到一些格式化数据,大多数处理方法中,JSONXML支持的数据类型就是基本数据类型,整型、浮点型、字符串、布尔等,如果开发者希望在传输数据的时候直接传输一个对象,那么就不得不想办法扩展基础的JSON(XML)语法。比如,JacksonFastjson这类序列化库,在JSON(XML)的基础上进行改造,通过特定的语法来传递对象. RMI使用java等语言内置的序列化方法,将一个对象转化成一串二进制

weixin_45694388的博客 6610

Java序列化反序列化(详解)

java序列化及可序列化讲解,代码清晰易懂。

qq_62414755的博客 4万+

Java 序列化反序列化的原理

在某些情况下,开发者可以通过自定义反序列化过程来处理循环引用。例如,可以在反序列化方法中手动管理循环引用的解析顺序,或者采用特定的数据结构来辅助循环引用的处理。这种方式需要开发者对反序列化过程有深入的理解,并具备一定的编程能力。总结一下,当一个对象在反序列化过程中具有循环依赖时,Java运行时系统会采取一些特殊的策略来构建对象图,以确保对象之间的关联关系能够正确地建立,并避免出现无限递归或者栈溢出等问题。

xxx 1693

Java 基础篇】Java序列化反序列化详解

本文详细介绍了Java序列化反序列化的原理、使用方法常见应用场景。通过实现接口,可以实现对象的序列化反序列化序列化反序列化是一种重要的机制,可以实现对象的持久化存储、网络传输缓存等功能。希望本文对你理解应用Java序列化反序列化有所帮助!

繁依Fanyi的博客 7350

java序列化反序列化详解及示例

对于序列化接口Serializable接口是一个标识接口,它的主要作用就是标识这个对象是可序列化的,jre对象在传输对象的时候会进行相关的封装。类 ObjectInputStream ObjectOutputStream 是高层次的数据流,它们包含序列化反序列化对象的方法。上面的方法序列化一个对象,并将它发送到输出流。该方法从流中取出下一个对象,并将对象反序列化。它的返回值为Object,因此,你需要将它转换成合适的数据类型。

alanchanchn的专栏 8万+

Java 序列化反序列化详解

/ 不会被默认序列化// 自定义序列化// 先执行默认序列化// 手动处理transient字段(可以加密后再保存)// 自定义反序列化// 先执行默认反序列化// 手动恢复transient字段(解密)// 加密方法(示例)// 实际项目中使用更安全的加密算法// 解密方法(示例)// 其他代码...序列化是将对象转为字节序列,反序列化是其逆过程实现Serializable接口是基础要求显式声明serialVersionUID可以避免版本问题。

JAVA爱好者的专栏 612

Java序列化反序列化(超详解)

序列化是什么意思?反序列化是什么意思?为什么要使用序列化

多敲代码防脱发的博客 3240

Java序列化以及反序列化详解

Java序列化以及反序列化详解

ks_1998的博客 5195

Java序列化反序列化实战详解

本文介绍了Java序列化反序列化的核心概念应用。序列化是将Java对象转换为字节流以便存储或传输,反序列化则是将字节流恢复为对象。文章详细展示了字符串对象的序列化/反序列化实现过程,包括使用FileOutputStream/ObjectOutputStream写入FileInputStream/ObjectInputStream读取。同时探讨了transient关键字的作用(禁止属性序列化Externalizable接口的用法(通过重写方法实现更灵活的序列化控制)。典型应用场景包括对象持久化、网

2302_80464795的博客 245

Java序列化反序列化详解

→ 对象→字节序列;→ 字节序列→对象;(版本控制)、transient(排除临时字段);核心价值:支持数据持久化、网络传输、跨语言交互、缓存优化,是复杂Java程序(如分布式系统、客户端/服务器应用)的基础能力。

LiLiYuan.的博客 806

详解Java反序列化漏洞

如果需要将某个对象保存到磁盘上或者通过网络传输,那么这个类应该实现 Serializable 接口或者Externalizable接口之一。使用到JDK中关键类 :ObjectOutputStream (对象输出流) ObjectInputStream (对象输入流)ObjectOutputStream 类中:通过使用 writeObject (Object object) 方法,将对象以二进制格式进行写入。ObjectInputStream类中:

爱玩游戏的黑客的博客 946

Java反序列化漏洞详解

 Java反序列化漏洞从爆出到现在快2个月了,已有白帽子实现了jenkins,weblogic,jboss等的代码执行利用工具。本文对于Java反序列化的漏洞简述后,并对于Java反序列化的Poc进行详细解读。 Java反序列化漏洞简介 Java序列化就是把对象转换成字节流,便于保存在内存、文件、数据库中,Java中的ObjectOutputStream类的writeObject

fengling59的专栏 4158

Java序列化反序列化详解

Java 中,序列化是将对象转换为字节序列的过程,而反序列化则是将字节序列转换回对象的过程。通过本文的介绍,我们深入了解了 Java序列化反序列化的基本概念、实际应用以及相关的注意事项。欢迎来到本篇博客,今天我们将深入研究 Java 中的序列化反序列化,这是在分布式系统持久化存储中经常遇到的重要概念。在网络中传递对象时,将对象序列化后通过网络传输,接收方再进行反序列化。将 Java 对象序列化后存储到文件或数据库中,便于后续读取使用。序列化版本号,用于在反序列化时验证对象的版本一致性。

私聊前往站内信:https://i.csdn.net/#/msg/chat/weixin_44976692 2万+

java序列化反序列化详解

如果默认的序列化机制不符合需求,可以通过实现方法来自定义序列化反序列化的行为。Java序列化是一个复杂但强大的机制,允许开发者轻松地持久化传输对象。虽然它对于简单的用途来说可能显得有些重,但它提供了一种标准方式来处理对象的深复制,以及对象状态的保存恢复。正确使用Java序列化需要对其工作原理有深入的理解,尤其是在涉及版本控制自定义序列化行为时。

2401_83707780的博客 2942

java基础】对象序列化反序列化详解

在上面,我们知道看transient关键字标识之后不会被序列化,于是b字段就为null,这里我们使用自定义序列化机制来解决这个问题。序列化机制为单个的类提供了一种方式,去向默认的读写行为添加验证或任何其他想要的行为。之后,数据域就再也不会被自动序列化,取而代之的是调用这些方法。我们只需要在A类中添加这2个方法,然后编写对应的方法即可out . writeUTF("我是B--通过自定义方式实现序列化");} }

秃头披风侠的博客 2725

Java序列化反序列化详解

Java序列化反序列化一、序列化是什么?二、反序列三、为什么需要序列化2.读入数据总结欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出导入导出导入 提示:文章写完后,目录可以自动生成,如何生成可参考右边

lovetheoneY的博客 314

Java序列化反序列化详解

Java序列化反序列化Java编程中重要的一个部分,在需要进行对象的跨进程、跨网络传输等场景中,会带来很大的便利。然而,在使用过程中,需要注意版本兼容性、性能影响以及安全问题,并对可能的安全漏洞进行防范。通过理解正确使用Java序列化机制,我们可以更有效地存储传输对象状态。

zhzjn的博客 1462

详解Java 对象序列化反序列化

java程序员都了解过有关字节流字符流的使用,当时我们对于将一个对象输出到流中的操作,使用DataOutputStream流将该对象中的每个属性值逐个输出到流中,读出时相反。在我们看来这种行为实在是繁琐,尤其是在这个对象中属性值很多的时候。基于此,Java中对象的序列化机制就可以很好的解决这种操作。...

Chenhui98的博客 465

Java对象的序列化(Serialization)反序列化详解

1.序列化反序列化 序列化(Serialization)是将对象的状态信息转化为可以存储或者传输的形式的过程,一般将一个对象存储到一个储存媒介,例如档案或记忆体缓冲等,在网络传输过程中,可以是字节或者XML等格式;而字节或者XML格式的可以还原成完全相等的对象,这个相反的过程又称为反序列化; 2.Java对象的序列化反序列化Java中,我们可以通过多种方式来创建对象,并且只要对象...

OceanSky的专栏 12万+
上一篇: Spring Cloud gateway 三种方式注入内存马(详细过程)
pyth0nn
博客等级 码龄4年 1285粉丝 12原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pyth0nn

送人玫瑰,手留余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值