欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

单例模式如何防止反射攻击

程序员文章站 2024-01-24 08:59:46
...

单例模式例子:

public class Single {
    private Single ()  {//私有化构造方法
    }
    private static volatile Single instance = null;
    public static synchronized Single getInstance() {
        if(instance==null){
            instance = new Single();//在此方法内创建对象
        }
        return instance;//返回所创建的对象
    }
}

以上代码若采用反射来创建对象就会翻车了!!
例子:

class Main{
    public static void main(String[] args) throws Exception {
        Class clazz = Single.class;
        Constructor constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        Single single = Single.getInstance();
        Single single1 = (Single) constructor.newInstance();
        System.out.println(single==single1);
    }
}

输出:
单例模式如何防止反射攻击
这方法如何解决呢?
暴力反射调取了类中的私有化构造器方法,而instance属性是静态的,所以可以判断instance是否为null,若不是null,则抛出异常警告

代码如下:

public class Single {
    private Single ()  {
        if(instance!=null){
            throw new RuntimeException("禁止使用反射调用!");
        }
    }
    private static volatile Single instance = null;
    public static synchronized Single getInstance() {
        if(instance==null){
            instance = new Single();
        }
        return instance;
    }
}

运行结果如下:
单例模式如何防止反射攻击
成功解决!

在这读者可能会有个问题,以上只使用了一次反射来调取构造方法创建对象,若两次创建对象都采用反射的方式呢?该如何解决?
例如

class Main{
    public static void main(String[] args) throws Exception {
        Class clazz = Single.class;
        Constructor constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        Single single1 = (Single) constructor.newInstance();
        Single single = (Single) constructor.newInstance();
        System.out.println(single==single1);
    }
}

很遗憾,这种情况下若要坚持采用懒汉式的单例模式是不能解决的。
只能够使用饿汉式的单例模式解决:

public class Single {
    private Single ()  {
        if(instance!=null){
            throw new RuntimeException("禁止使用反射调用!");
        }
    }
    private static volatile Single instance = new Single();
    public static Single getInstance() {
//        if(instance==null){
//            instance = new Single();
//        }
        return instance;
    }
}
class Main{
    public static void main(String[] args) throws Exception {
//        Single single1 = Single.getInstance();
//        Single single2 = Single.getInstance();
//        System.out.println(single1==single2);
        Class clazz = Single.class;
        Constructor constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
//        Single single = Single.getInstance();
        Single single1 = (Single) constructor.newInstance();
        Single single = (Single) constructor.newInstance();
        System.out.println(single==single1);
    }
}

单例模式如何防止反射攻击