java反序列化

序列化/反序列化原理

  • 简单来说就是:
    • writeObject()方法序列化
    • readObject()方法反序列化
  • 一个对象要想被序列化,该对象所属的类必须实现Serializable接口
    • 序列化:对象 -> 字符串
    • 反序列化:字符串 -> 对象

对象的序列化主要有两种用途:

把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中(持久化对象);
在网络上传送对象的字节序列(网络传输对象)。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java 对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为 Java 对象。

概述

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

  2. 序列化分为两大部分:序列化和反序列化。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例。

    1. 为什么需要序列化与反序列化化
      1. 我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的。如何做到呢?这就需要Java序列化与反序列化了。换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。
      2. 当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。
        1. 想把内存中的对象保存到一个文件中或者数据库中时候;
        2. 想用套接字在网络上传送对象的时候;
        3. 想通过RMI传输对象的时候
    2. 一些应用场景,涉及到将对象转化成二进制,序列化保证了能够成功读取到保存的对象。
  3. 几种常见的序列化和反序列化协议

    1. XML&SOAP
      1. XML 是一种常用的序列化和反序列化协议,具有跨机器,跨语言等优点
      2. SOAPSimple Object Access protocol) 是一种被广泛应用的,基于 XML 为序列化和反序列化协议的结构化消息传递协议,它使应用使用http协议来交换信息
    2. JSONJavascript Object Notation
    3. Protobuf
  4. 为什么会产生安全问题

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

    1. 只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常)
    2. Serializable 接口
      1. 是 Java 提供的序列化接口,它是一个空接口
      1. public interface Serializable {
      2. }
  1. Serializable 用来标识当前类可以被 ObjectOutputStream 序列化,以及被 ObjectInputStream 反序列化。

  2. Serializable 接口的基本使用

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

    1. 序列化类的属性没有实现 Serializable 那么在序列化就会报错
    2. 在反序列化过程中,它的父类如果没有实现序列化接口,那么将需要提供无参构造函数来重新创建对象。
    3. 一个实现 Serializable 接口的子类也是可以被序列化的。
    4. 静态成员变量是不能被序列化
      1. 序列化是针对对象属性的,而静态成员变量是属于类的。
    5. transient 标识的对象成员变量不参与序列化
  4. 序列化ID

    1. 可以看到,我们在进行序列化时,加了一个serialVersionUID字段,这便是序列化ID
    2. private static final long serialVersionUID = 1L;
    3. 这个序列化ID起着关键的作用,它决定着是否能够成功反序列化!java的序列化机制是通过判断运行时类的serialVersionUID来验证版本一致性的,在进行反序列化时,JVM会把传进来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。
    4. 即序列化ID是为了保证成功进行反序列化
  5. 可能的形式

    1. 入口类的readObject直接调用危险函数
    2. 入口类参数中包括可控类,该类有危险方法,readObject时调用
    3. 入口类中包含可控类,该类又调用其他危险函数的类,readObject时调用。
    4. 比如类型定义为Object,调用equals/hashcode/toString(相同类型,相同函数)
  6. 构造函数/静态代码块等在类加载的时候隐式执行

共同条件

  1. 继承Serialize
  2. 入口类 source (重写readObject 参数类型宽泛 最好JDK自带) Map
    1. HashMap继承了serialize,满足参数类型宽泛,也是JDK自带的,也重写了readObject,是一个很完美的入口类
      1. 会进行数据传输,所以继承了serialize
      2. 本身就是键值对,满足参数类型宽泛
      3. 因为hashmap需要保证键的唯一性,就要计算键的hashcode,如果键是对象的话,在不同的JVM实现中计算得出的hash值可能是不同的,所以他必须重新实现他的readobject方法
  3. 调用类 gadget chain
  4. 执行类 sink (rec ssrf 写文件等) 最重要的部分
/封装serializepublic static void serialize(Object object) throws IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));

● oos.writeObject(object);}//封装unserializepublic static Object unserialize(String Filename) throws IOException, ClassNotFoundException {ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));Object obj = ois.readObject();return obj;}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

YY13172

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值