枚举单例的抗序列化攻击演示(一)
public enum EnumInstance {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumInstance getInstance() {
return INSTANCE;
}
}
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
serializableAttack();
}
public static void serializableAttack() throws Exception {
EnumInstance instance = EnumInstance.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("enum_singleton_file"));
oos.writeObject(instance);
File file = new File("enum_singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
EnumInstance newInstance = (EnumInstance)ois.readObject();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(instance == newInstance);
}
}
输出:
INSTANCE
INSTANCE
true
枚举单例的抗序列化攻击演示(二)
- 持有date的单例枚举实例;
public class Test {
public static void main(String[] args) throws Exception {
serializableAttack2();
}
public static void serializableAttack2() throws Exception {
EnumInstance instance = EnumInstance.getInstance();
instance.setData(new Object());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("enum_singleton_file"));
oos.writeObject(instance);
File file = new File("enum_singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
EnumInstance newInstance = (EnumInstance)ois.readObject();
System.out.println(instance.getData());
System.out.println(newInstance.getData());
System.out.println(instance.getData() == newInstance.getData());
System.out.println(instance == newInstance);
}
}
输出:
java.lang.Object@14514713
java.lang.Object@14514713
true
true
枚举单例抗序列化攻击源码分析
- 在反序列化的时候,通过描述符desc拿到了待反序列化的枚举(EnumInstance)的Class类型c1;
- readString(false) 又拿到了待序列化的枚举类中枚举实例(INSTANCE)的名字name;
-
根据Enum.valueOf(Class, String) 就可以取到 EnumInstance 中的 INSTANCE 实例,其原理类似于 readResolve() 方法的添加;
1.png