java中反序列化的遍历_探秘Java反序列化漏洞一:序列化与反序列化

最近在看Java反序列化漏洞方面的文章,感谢各位大佬的分享。由此做一个整理,并加入自己的理解。

序列化与反序列化

序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。一般将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等。在网络传输过程中,可以是字节或是XML等格式。而字节的或XML编码格式可以还原完全相等的对象。这个相反的过程又称为反序列化。

简单来说序列化是用于将对象转换成二进制串存储,而反序列化即为将二进制串转换成对象。

5c6127ea8039e7e0fd963d32ad16aa2e.png

为什么要序列化

在运行Java中,我们会通过各种途径创建对象,这些对象事实上都是位于JVM的堆内存中,伴随着其运行而存在。一旦当JVM停止运行,这些对象的状态也就随之消失。在实际中,我们需要将这些对象持久下来并且在需要时候读出来,或者为了节省内存,这时候就需要使用序列化。

对象序列化机制(object serialization)是Java语言内建的一种对象持久化方式,通过对象序列化,可以把对象的状态保存为字节数组,并且可以在有需要的时候将这个字节数组通过反序列化的方式再转换成对象。对象序列化可以很容易的在JVM中的活动对象和字节数组(流)之间进行转换。

使用场景

http参数,cookie,sesion,存储方式可能是base64(rO0), 压缩后的base64(H4sl),MII等

Servlets HTTP,Sockets,Session管理器 包含的协议就包括 JMX,RMI,JMS,JNDI等(\xac\xed)

xml Xstream,XMLDecoder等(HTTP Body:Content- Type:application/xml)

json(Jackson,fastjson)http请求中包含

代码实现

相关接口及类

Java为了方便开发人员将Java对象进行序列化及反序列化提供了一套方便的API来支持。其中包括以下接口和类:

java.io.Serializable

java.io.Externalizable

ObjectOutput

ObjectInput

ObjectOutputStream

ObjectInputStream

使用时可序列化的对象需要实现 java.io.Serializable 接口或者 java.io.Externalizable 接口。

以实现 Serializable 接口为例,Serializable 仅是一个标记接口,并不包含任何需要实现的具体方法。实现该接口只是为了声明该Java类的对象是可以被序列化的。实际的序列化和反序列化工作是通过ObjectOuputStream和ObjectInputStream来完成的。ObjectOutputStream 的 writeObject 方法可以把一个Java对象写入到流中,ObjectInputStream 的 readObject 方法可以从流中读取一个 Java 对象。在写入和读取的时候,虽然用的参数或返回值是单个对象,但实际上操纵的是一个对象图,包括该对象所引用的其它对象,以及这些对象所引用的另外的对象。Java 会自动帮你遍历对象图并逐个序列化。除了对象之外,Java 中的基本类型和数组也是可以通过 ObjectOutputStream 和 ObjectInputStream 来序列化的。

示例代码

序列化

public class Ser implements Serializable{

private static final long serialVersionUID = 1L;

public int num=911;

public static void main(String[] args) {

try {

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.obj"));

Ser ser=new Ser();

oos.writeObject(ser);//序列化关键函数

oos.flush(); //缓冲流

oos.close(); //关闭流

} catch (IOException e) {

e.printStackTrace();

}

}

}

可以看到,在序列化后当前目录下生成了一串二进制表示的字节数组文件object.obj

接下来我们执行反序列化读出其对象中的参数

反序列化

public class DeSer {

public static void main(String[] args) throws ClassNotFoundException, IOException {

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.obj"));

Ser s = (Ser) ois.readObject();

System.out.println(s.num);

ois.close();

}

}

a618d42fadae0368a7c55f9bce3130f9.png

存储格式

序列化的文件二进制字节数据如下图

667a01921df732a2baec316cf2620b8f.png

1.序列化文件头

AC ED :STREAM_MAGIC声明使用了序列化协议

00 05 :STREAM_VERSION序列化协议版本

73 :TC_OBJECT声明这是一个新的对象

2.序列化类的描述 在这里是Ser类

72 :TC_CLASSDESC声明这里开始一个新的class

00 11 :class名字的长度是17个字节

63 6E 2E 72 75 69 30 2E 74 65 73 74 31 2E 53 65 72 :Ser的完整类名

00 00 00 00 00 00 00 01 :serialVersionUID,序列化ID,如果没有指定,则会由算法随机生成一个8字节的ID

02 :标记号,声明该类支持序列化

00 01:该类所包含的域的个数为1

3.对象中各个属性的描述

49 :域类型,49代表I,也就是int类型

00 03 :域名字的长度为3

6E 75 6D :num属性的名称

4.对象的父类信息描述

这里没有父类,如果有,则数据格式与第二部分一样

5.对象属性的实际值

如果属性是一个对象,那么这里还将序列化这个对象,规则和第2部分一样

00 00 03 8F :911的数值

当然我们也可以使用工具SerializationDumper来查看其结构

021fbf455b18f9a3c9e0a445b0d23f93.png

注意

当父类实现了Serializable接口的时候,所有的子类都能序列化

子类实现了Serializable接口,父类没有,父类中的属性不能被序列化(不报错,但是数据会丢失)

如果序列化的属性是对象,对象必须也能序列化,否则会报错

反序列化的时候,如果对象的属性有修改或则删减,修改的部分属性会丢失,但是不会报错

在反序列化的时候serialVersionUID被修改的话,会反序列化失败

在存Java环境下使用Java的序列化机制会支持的很好,但是在多语言环境下需要考虑别的序列化机制,比如xml,json,或则protobuf

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值