Java中的单例模式防反序列化解决方案

一、readResolve()法

首先构造一个可序列化的单例模式类

public class User implements Serializable {
     private static final User instance=new User();
     public String name;
     public int age;

     private User()
     {
         name="Sean";
         age=23;
     }

     public static User getInstance()
     {
         return instance;
     }

}

利用反序列化实施破解工作

public class TestSelializable {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        User a=User.getInstance();

        ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream("C:/user.txt"));
        os.writeObject(a);
        os.flush();        //利用管道将实例a序列化输出到文件user.txt中
        os.close();

        ObjectInputStream is=new ObjectInputStream(new FileInputStream("C:/user.txt"));
        User b=(User) is.readObject();  //利用管道将user.txt中的实例反序列化输入进来作为对象b
        is.close();                     //这实际上就等于重新生成了另一个单例对象

        b.name="Moon";
        b.age=31;

        System.out.println("a's name:"+a.name+" "+"a's age:"+a.age);
        System.out.println("b's name:"+b.name+" "+"b's age:"+b.age);
        //输出对象a、b的信息,不同则证明反序列化破解了单例模式
    }

}

运行结果:

a's name:Sean a's age:23
b's name:Moon b's age:31

这就证明了单例模式遭到了反序列化的破坏

解决办法:

public class User implements Serializable {
     private static final User instance=new User();
     public String name;
     public int age;

     private User()
     {
         name="Sean";
         age=23;
     }

     public static User getInstance()
     {
         return instance;
     }

     //在单例类中添加readResolve()方法
     //每当JVM从文件中向内存反序列化新建一个对象时就对调用该方法,加入适当操作即可防止反序列化
     private Object readResolve()
     {
         return instance;
     }
}

再看修改后测试程序的运行结果:

a's name:Moon a's age:31
b's name:Moon b's age:31

a、b对象输出信息一致说明readResolve()防止反序列化破解成功


二、枚举法

先构造一个可序列化的单例模式枚举类

public enum UserEnum implements Serializable {
   instance;

    public String name="Sean";
    public int age=23;
}

利用类似的反序列化实施破解

public class TestSelializable {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        UserEnum a=UserEnum.instance;

        ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream("C:/userenum.txt"));
        os.writeObject(a);
        os.flush();        //利用管道将枚举实例a序列化输出到文件userenum.txt中
        os.close();

        ObjectInputStream is=new ObjectInputStream(new FileInputStream("C:/userenum.txt"));
        UserEnum b=(UserEnum) is.readObject();  //利用管道将user.txt中的枚举实例反序列化输入进来作为枚举实例b
        is.close();                     

        b.name="Moon";
        b.age=31;

        System.out.println("a's name:"+a.name+" "+"a's age:"+a.age);
        System.out.println("b's name:"+b.name+" "+"b's age:"+b.age);
        //输出枚举对象a、b的信息,不同则证明序列化破解了枚举单例模式
    }

}

运行结果:

a's name:Moon a's age:31
b's name:Moon b's age:31

枚举对象a、b输出相同的信息说明枚举天生就有防止反序列化破解的能力,可以放心使用

猜你喜欢

转载自blog.csdn.net/lovecaicaiforever/article/details/81584622