Java序列化方法

标签 java serialization serializable secure-coding

securecoding site 解释道:

Blockquote This noncompliant code example shows a class Ser with a private constructor, indicating that code external to the class should be unable to create instances of it. The class implements java.io.Serializable and defines public readObject() and writeObject() methods. Consequently, untrusted code can obtain the reconstituted objects by using readObject() and can write to the stream by using writeObject().

public class Ser implements Serializable {
  private final long serialVersionUID = 123456789;
  private Ser() {
    // initialize
  }
  public static void writeObject(final ObjectOutputStream stream)
    throws IOException {
    stream.defaultWriteObject();
  }
  public static void readObject(final ObjectInputStream stream)
      throws IOException, ClassNotFoundException {
    stream.defaultReadObject();
  }
}

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

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

任何帮助将不胜感激。

最佳答案

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

首先,正如您所指出的,由于这些方法被声明为静态的,因此序列化机制根本不会调用它们。 (序列化主要是基于库的,而不是基于 JVM。)问题是,如果您想使用这些方法自定义序列化格式,它根本行不通。无论您在这些方法中输入什么内容,都将使用默认的序列化格式。

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

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

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

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

但是,当引用的文章指出这将阻止攻击者创建不需要的实例时,它是不正确的。私有(private)构造函数将被反序列化绕过,这是正确的。但是,将 readObjectwriteObject 设为私有(private)将不会阻止攻击者反序列化任意数量的此类实例。这大概就是霸主所关心的。我可以轻松地编写自己的字节流,并使用我选择的任何内容,根据需要多次反序列化对象:

ObjectInputStream ois = new ObjectInputStream(myInputStream);
Ser anotherSerInstance = (Ser)ois.readObject();

为了防止这种情况发生,Ser 类必须在 readObject 中实现一些检查,如果想要防止反序列化,则抛出类似 InvalidObjectException 的异常。另一种方法是实现 readResolve 并返回已创建的实例(例如单例),而不是创建新实例。

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

关于Java序列化方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25201033/

相关文章:

java - HttpPost 响应不返回 json 对象

c - 未定义对 "tpl_map"的引用

javafx - Java "Could Not Serialize the Data"

java - SLF4J 按标记过滤日志消息

java - 回调是什么意思?

java - JBoss 7.0 Web 配置文件应用程序无法启动

.net - .NET 4 是否有内置的 JSON 序列化器/反序列化器?

java - JBoss 和 Resteasy : ClassNotFoundException while deserializing java-serialized object

database - Serializable 和 non Serializable 对象保存到数据库中的区别

c# - 如何序列化 CustomLineCap 类的实例