Java序列化方法

Java序列化方法,java,serialization,serializable,secure-coding,Java,Serialization,Serializable,Secure Coding,正如所解释的那样: 大宗报价 这个不符合规范的代码示例显示了一个带有私有构造函数的类Ser,表明该类外部的代码应该无法创建它的实例。该类实现java.io.Serializable并定义public readObject()和writeObject()方法。因此,不受信任的代码可以使用readObject()获得重构的对象,并可以使用writeObject()写入流 正如您所知,writeObject和readObject方法应该定义为private(也没有static关键字!),并且JVM不会

正如所解释的那样:

大宗报价 这个不符合规范的代码示例显示了一个带有私有构造函数的类Ser,表明该类外部的代码应该无法创建它的实例。该类实现java.io.Serializable并定义public readObject()和writeObject()方法。因此,不受信任的代码可以使用readObject()获得重构的对象,并可以使用writeObject()写入流

正如您所知,writeObject和readObject方法应该定义为private(也没有static关键字!),并且JVM不会调用这些方法

我的问题是:为什么这些方法是不安全的。这些方法甚至不能被JVM调用!!我想要一个示例代码,向我表明此代码可能不安全,攻击者可以访问我们的数据


任何帮助都将不胜感激。

这里显示的代码中肯定有一个bug,但它不是真正的安全漏洞,只是编程错误。不幸的是,安全编码网站在关于如何修复它的一些声明中是不正确的。见该条下面的评论;他们讨论了一些错误

首先,正如您所指出的,由于这些方法是声明为
静态的
,所以序列化机制根本不会调用它们。(序列化主要是基于库的,而不是基于JVM的。)错误在于,如果您想使用这些方法自定义序列化格式,它根本不起作用。无论在这些方法中放入什么,都将使用默认的序列化格式

(定制的
readObject
writeObject
方法除了调用默认的读/写例程之外什么也不做,这也有点奇怪,根本不提供定制,但这可能是为了示例而做的。)

这个代码不安全吗?不,不是真的。它只是不能按预期的方式工作

用户Powerlord询问攻击者是否不能直接调用
Ser.readObject(myInputStream)
。这是行不通的,因为只允许在对象反序列化期间调用
defaultReadObject
方法。如果不是,它将抛出
NotActiveException

此代码的修复方法是更改方法,使其成为
私有
实例方法,而不是
公共静态
方法。这将导致序列化机制调用这些方法,以便它们可以实现一些格式自定义

但是,当引用的文章声明这将阻止攻击者创建不需要的实例时,它是不正确的。反序列化将绕过私有构造函数是正确的。但是将
readObject
writeObject
设置为私有将而不是阻止攻击者反序列化任意数量的此类实例。这可能是Powerlord所关心的。我可以轻松地编造自己的字节流,并从中反序列化对象,次数可以根据我的需要,使用我选择的任何内容:

ObjectInputStream ois = new ObjectInputStream(myInputStream);
Ser anotherSerInstance = (Ser)ois.readObject();
为了防止出现这种情况,
Ser
类必须在
readObject
中实现一些检入,并抛出类似于
InvalidObjectException
的东西,如果它想防止反序列化的话。另一种方法是it实现
readResolve
,并返回一个已经创建的实例(例如单例实例),而不是创建一个新实例


有关进一步的讨论,请参见Bloch,《有效Java》,第74-78项。请注意,如果您想要单例,建议使用
enum
而不是
readResolve

站点不正确。文件中明确指出,
writeObject()
的签名是

private void writeObject(ObjectOutputStream stream)
    throws IOException;
同样的,这是


如果将它们设置为
公共
静态
,则不会调用它们。它们都在这里。

为什么JVM不调用它们?如何阻止EvilClass调用
Ser.readObject(myInputStream)
?@Powerlord查看我的答案。
private void writeObject(ObjectOutputStream stream)
    throws IOException;
private void readObject(ObjectInputStream stream)
    throws IOException, ClassNotFoundException;