java序列化_Java Web安全 || Java基础 Java 序列化/反序列化

点击上方“凌天实验室”,“星标或置顶公众号”

漏洞、技术还是其他,我都想第一时间和你分享

50daac433c720589e4d1ca5cd3558e72.png

【历史】已连载更新全部内容:【菜单栏】-【JAVA SEC】

在Java中实现对象反序列化非常简单,实现java.io.Serializable(内部序列化)java.io.Externalizable(外部序列化)接口即可被序列化(Externalizable接口只是实现了java.io.Serializable接口)。

反序列化类对象时有如下限制:

  1. 被反序列化的类必须存在。

  2. serialVersionUID值必须一致。

除此之外,反序列化类对象是不会调用该类构造方法的,因为在反序列化创建类实例时使用了sun.reflect.ReflectionFactory.newConstructorForSerialization创建了一个反序列化专用的Constructor(反射构造方法对象),使用这个特殊的Constructor可以绕过构造方法创建类实例(前面章节讲sun.misc.Unsafe 的时候我们提到了使用allocateInstance方法也可以实现绕过构造方法创建类实例)。

使用反序列化方式创建类实例代码片段:

package com.anbai.sec.serializes;

程序运行结果:

2b650cea

具体细节可参考 不用构造方法也能创建对象。

c918fdb58c867d6424523a66f35998d0.png

ObjectInputStream、ObjectOutputStream

java.io.ObjectOutputStream类最核心的方法是writeObject方法,即序列化类对象。

java.io.ObjectInputStream类最核心的功能是readObject方法,即反序列化类对象。

所以,只需借助ObjectInputStreamObjectOutputStream类我们就可以实现类的序列化和反序列化功能了。

java.io.Serializable

java.io.Serializable是一个空的接口,我们不需要实现java.io.Serializable的任何方法,代码如下:

public 

您可能会好奇我们实现一个空接口有什么意义?其实实现java.io.Serializable接口仅仅只用于标识这个类可序列化。实现了java.io.Serializable接口的类原则上都需要生产一个serialVersionUID常量,反序列化时如果双方的serialVersionUID不一致会导致InvalidClassException 异常。如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID值。

DeserializationTest.java测试代码如下:

package com.anbai.sec.serializes;

程序执行结果如下:

DeserializationTest类序列化后的字节数组:[-84, -19, 0, 5, 115, 114, 0, 44, 99, 111, 109, 46, 97, 110, 98, 97, 105, 46, 115, 101, 99, 46, 115, 101, 114, 105, 97, 108, 105, 122, 101, 115, 46, 68, 101, 115, 101, 114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 84, 101, 115, 116, 74, 36, 49, 16, -110, 39, 13, 76, 2, 0, 2, 76, 0, 5, 101, 109, 97, 105, 108, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 76, 0, 8, 117, 115, 101, 114, 110, 97, 109, 101, 113, 0, 126, 0, 1, 120, 112, 116, 0, 17, 97, 100, 109, 105, 110, 64, 106, 97, 118, 97, 119, 101, 98, 46, 111, 114, 103, 116, 0, 2, 121, 122]
用户名:yz,邮箱:admin@javaweb.org

核心逻辑其实就是使用ObjectOutputStream类的writeObject方法序列化DeserializationTest类,使用ObjectInputStream类的readObject方法反序列化DeserializationTest类而已。

简化后的代码片段如下:

// 序列化DeserializationTest类

ObjectOutputStream序列化类对象的主要流程是首先判断序列化的类是否重写了writeObject方法,如果重写了就调用序列化对象自身的writeObject方法序列化,序列化时会先写入类名信息,其次是写入成员变量信息(通过反射获取所有不包含被transient修饰的变量和值)。

java.io.Externalizable

java.io.Externalizablejava.io.Serializable几乎一样,只是java.io.Externalizable接口定义了writeExternalreadExternal方法需要序列化和反序列化的类实现,其余的和java.io.Serializable并无差别。

java.io.Externalizable.java:

public 

ExternalizableTest.java测试代码如下:

package com.anbai.sec.serializes;

程序执行结果如下:

84, -

鉴于两者之间没有多大差别,这里就不再赘述。

c918fdb58c867d6424523a66f35998d0.png

自定义序列化(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 

当我们序列化DeserializationTest类时,会自动调用(反射)该类的writeObject(ObjectOutputStream oos)方法,反序列化时候也会自动调用readObject(ObjectInputStream)方法,也就是说我们可以通过在需要序列化/反序列化的类中定义readObjectwriteObject方法从而实现自定义的序列化和反序列化操作,和当然前提是被序列化的类必须有此方法且方法的修饰符必须是private

**如果您在阅读文章的时候发现任何问题都可以通过Vchat与我们联系,也欢迎大家加入javasec微信群一起交流。

Vchat获取方式:对话框发送“javasec”

d9376c4e37a6d99a6ab7c091c73168da.png 9f54b4da1960c66e3ad342bfd9af268a.png凌天实验室

凌天实验室,是安百科技旗下针对应用安全领域进行攻防研究的专业技术团队,其核心成员来自原乌云创始团队及社区知名白帽子,团队专业性强、技术层次高且富有实战经验。实验室成立于2016年,发展至今团队成员已达35人,在应用安全领域深耕不辍,向网络安全行业顶尖水平攻防技术团队的方向夯实迈进。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值