从ObjectInputStream读取对象时如何确保安全



我尝试了以下实验(这只是一个伪代码):

class Server {
public static void main(final String args[]) {
final ServerSocket server = new ServerSocket(PORT);
final Socket client = server.accept();
final ObjectInputStream stream = new ObjectInputStream(client.getInputStream());
final Object object = stream.readObject();
// Can we hope that standard toString method will be called?
System.out.println(object.toString());
}
}

然后创建了一个恶意对象:

class MaliciousObject extends Object implements Serializable {
private static final long serialVersionUID = 1L;
@Override
public String toString() {
return "I am malicious object";
}
}

最后使用另一个程序向服务器发送了一个恶意对象的实例

public static void main(final String args[]) {
final Socket socket = new Socket();
socket.connect(serversAddress, TIMEOUT);
final ObjectOutputStream stream = new ObjectOutputStream(socket.getOutputStream());
stream.writeObject(new MaliciousObject());
}

服务器打印到屏幕上的输出是

I am malicious object

因此,黑客似乎可以实现一个类扩展对象,覆盖任何方法M来执行一些恶意代码,然后通过网络发送这个对象,希望服务器调用M。

因此,我的问题是:如何防御?如果我们从ObjectInputStream中读取对象,我们如何确保它们没有格式错误?

附带问题是,在这种情况下,从ObjectInputStream读取对象时是否涉及Java类加载器?

因此,黑客似乎可以实现一个类扩展对象,覆盖任何方法M来执行一些恶意代码,然后通过网络发送该对象,希望服务器调用M。

否。对象不包含代码。该类包含代码,并且该类未序列化。在任何序列化之前,您已经有了"被黑客入侵"的代码,所以您已经有问题了。

我的问题是:如何防御这种情况?如果我们从ObjectInputStream中读取对象,我们如何确保它们没有格式错误?

您不能,但只有当生成所示输出的编译代码已经存在于CLASSPATH中时,才会出现这种情况,因此您已经存在序列化或没有序列化的问题。请注意,序列化不会序列化

作为一个附带问题,在这种情况下,从ObjectInputStream读取对象时是否涉及Java类加载器?

是。

NB伪码不是一个实验,而是一个思想实验。我建议你在现实世界中试试。

也许serialVersionUID可以帮助防御这种情况。您可以阅读:http://www.mkyong.com/java-best-practices/understand-the-serialversionuid/

什么是serialVersionUID?我为什么要使用它?

最新更新