反射攻击解决方案及原理分析

  反射可以通过修改私有构造器的访问权限,或者修改单例类的某些属性值,来获取新的实例,从而破坏单例模式。

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        HungrySingleton hungrySingleton = HungrySingleton.getInstance();
        Class objectClass = HungrySingleton.class;
        Constructor declaredConstructor = objectClass.getDeclaredConstructor();
        // 修改私有构造器的访问权限
        declaredConstructor.setAccessible(false);
        HungrySingleton newHungrySingleton = (HungrySingleton) declaredConstructor.newInstance();
        System.out.println(hungrySingleton);
        System.out.println(newHungrySingleton);
        System.out.println(hungrySingleton==newHungrySingleton);
    }
}  

输出结果:
  designmodel.singleton.HungrySingleton@61bbe9ba
  designmodel.singleton.HungrySingleton@610455d6
  false

  静态内部类和饿汉式可以在构造器内判断单例是否为空防止反射,但是懒汉式等延迟加载的单例模式不行,在多线程情况下不能保证反射创建的实例顺序较后。

private HungrySingleton(){
        if (hungrySingleton!=null){
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }  

  针对懒汉式单例模式,即使在类里添加判断参数判定该实例是否已经产生来阻止反射攻击仍然没用,因为反射可以任意修改类的属性值。

public class LazySingleton {

    private static LazySingleton lazySingleton = null;
    private static boolean flag = true;

    private LazySingleton(){
        if (flag){
            flag=false;
        }else {
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }

    public static LazySingleton getInstance(){
        if (lazySingleton==null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }

    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        LazySingleton instance = LazySingleton.getInstance();
        Class objectClass = LazySingleton.class;
        Constructor c = objectClass.getDeclaredConstructor();

        Field flag = objectClass.getDeclaredField("flag");
        flag.setAccessible(true);
        flag.set(instance,true);
        LazySingleton newInstance = (LazySingleton) c.newInstance();

        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance==newInstance);
    }
}  

输出结果:
  designmodel.singleton.LazySingleton@610455d6
  designmodel.singleton.LazySingleton@511d50c0
  false

发布了11 篇原创文章 · 获赞 1 · 访问量 261

猜你喜欢

转载自blog.csdn.net/Introncheng/article/details/103132147