枚举单例模式——可抵御反射攻击和序列化攻击

枚举类:

public enum EnumSingleTon {
    /**
     * 唯一实例
     */
    uniqueEnum(),;

}

主函数:

  public static void main(String[] args) throws Exception {
        EnumSingleTon uniqueEnum = EnumSingleTon.uniqueEnum;
        //反射攻击,(枚举的构造函数默认是私有的)
        //这里int.class,基本类型还能这么用,长见识了
        Constructor declaredConstructor = uniqueEnum.getClass().getDeclaredConstructor(String.class, int.class);
        declaredConstructor.setAccessible(true);
        //newInstance()方法中会判断类此构造器所属类是否有enum修饰,如果有,禁止实例   if ((clazz.getModifiers() & Modifier.ENUM) != 0)
//        EnumSingleTon enumSingleTon = declaredConstructor.newInstance("secondObj", 2);// IllegalArgumentException
        /**
         * 所以,以上证明枚举可以抵御反射攻击
         */

        //序列化攻击
        File file = new File("my.txt");
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
        try (ObjectOutputStream objOutStream = new ObjectOutputStream(bos)) {
            objOutStream.writeObject(uniqueEnum);
        }

        FileInputStream fileInputStream = new FileInputStream(file);
        BufferedInputStream bis = new BufferedInputStream(fileInputStream);
        EnumSingleTon serialEnum;
        try (ObjectInputStream objInStream = new ObjectInputStream(bis)) {
            serialEnum = (EnumSingleTon) objInStream.readObject();
        }
        System.out.println(uniqueEnum == serialEnum);
      /*  true ,反序列化得到的对象本内存中的原对象竟然是同一个对象,
        这就是枚举序列化神奇的地方,其序列化只是序列化对象名,反序列化时,根据
        EnumSingleTon enumSingleTon = EnumSingleTon.valueOf("serial-name");
        根据枚举对象名,直接引用已经存在的枚举对象,不会去自己创建*/

    }

结论:枚举类实现的单列模式,可以完美的防御反射攻击和序列化攻击

if ((clazz.getModifiers() & Modifier.ENUM) != 0)

说明反射在通过newInstance创建对象时,会检查该类是否ENUM修饰,如果是则抛出异常,反射失败。
参考:https://www.cnblogs.com/chiclee/p/9097772.html

你可能感兴趣的:(枚举单例模式——可抵御反射攻击和序列化攻击)