美文网首页
你写的单例一定安全吗?

你写的单例一定安全吗?

作者: helang1991 | 来源:发表于2018-09-07 11:28 被阅读26次

前言:

在并发环境中,我们可以用各种锁来保持单例的线程安全,当然这是从业务角度来考虑的;但是,从一个攻击者的角度来看,你的单例也许只保证了线程安全,当攻击者通过反射new出单例的实例时候(反射的可以改变你的私有构造函数),那攻击者就可以控制你的单例干很多坏事

举例:

单例代码:

/** * 
懒汉式单例(简单点),不考虑多线程并发的模型 
*/
public class MyInstance {    
private static MyInstance instance;    
   private MyInstance(){     
}     
public static MyInstance getInstance(){        
  if (instance == null){           
       instance = new MyInstance();      
    }        
    return instance;    
  }
}

攻击代码:

import java.lang.reflect.Constructor;

public class Main {

    public static void main(String[] args){

        System.out.println(MyInstanceEnum.INSTANCE.getMyInstance());
        try
        {
            Class<MyInstanceEnum> classType = MyInstanceEnum.class;

            Constructor<MyInstanceEnum> constructor = classType.getDeclaredConstructor(null);
            constructor.setAccessible(true);//关键代码,将这个构造函数的权限设置为可进入的


            MyInstanceEnum myInstanceHack = constructor.newInstance();


            System.out.println(myInstanceHack);


        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

    }
}

攻击结果:

从结果来看,两个对象的地址是不一样的,那么攻击者就可以利用这个方式,干很多越权的事情。

image.png

如何防范呢?

其实,问题所在就是那个构造函数被攻击了,因此,我们只要保护好构造函数,就能基本防御这种攻击

方式一:

利用一个静态变量,保证构造函数只被掉一次

/**
 * 懒汉式单例(简单点),不考虑多线程并发的模型
 */
public class MyInstance {
    private static MyInstance instance;
    private static boolean isUsed;
 
    private MyInstance(){
 
        if (isUsed){
            //抛出异常
            throw new RuntimeException();
        }else {
            isUsed = true;
        }
 
 
 
    }
 
    public static MyInstance getInstance(){
        if (instance == null){
            instance = new MyInstance();
        }
        return instance;
    }
}

方式二:

利用枚举的特性:每个枚举量只会实例化一次,也就是枚举类的单例:


public enum MyInstanceEnum {
    INSTANCE;
    private MyInstance2 myInstance;
 
    MyInstanceEnum(){
        myInstance = new MyInstance2();
    }
 
    public MyInstance2 getMyInstance() {
        return myInstance;
    }
}

攻击时报错

image.png

总结:

当然,反射被设计出来,肯定不是用来攻击的,它的作用可以很多依赖注入的框架中,比如Spring各种框架,JSON解析等很多方面。(不晓得从哪里看到一句话:人的血液循环是复杂但是有规律的,打针(反射)在中间介入这个循环如果没摸清楚循环规律而乱戳表面看似达到效果,实际会引发其他问题)

相关文章

  • 你写的单例一定安全吗?

    前言: 在并发环境中,我们可以用各种锁来保持单例的线程安全,当然这是从业务角度来考虑的;但是,从一个攻击者的角度来...

  • 设计模式

    手写单例模式(线程安全) 你知道几种设计模式?单例模式是什么?Spring中怎么实现单例模式?

  • 关于单例模式

    静态实现单例模式能较少的使用内存,也具备一定的安全性 饿汉模式实现单例模式的原理是要一次单例对象就创建一个单例对象...

  • 单例

    单例,是Java中很重要的一个设计模式。 实现单例是要考虑并发(线程安全)问题的。 如何实现一个线程安全的单例?你...

  • Controller是单例模式的吗?如何保证线程安全?

    Controller是单例模式的吗?如何保证线程安全? 答:Controller是单例的,也就是说并发请求调用Co...

  • Double Check Lock是存在问题的

    Double Check Lock 上述代码,能保证单例方式的线程安全性吗? 答案是肯定的。它既能实现单例模式,又...

  • 设计模式之你真的了解单例模式么?

    问题思考 你知道什么是单例模式么?你能写出一个性能有保障并且安全的单例模式么? 首先我们先明确单例模式的概念,单例...

  • 你写的单例对吗

    单例模式是设计模式中最容易理解、最容易上手的设计模式,同时也是最容易出错的设计模式。它的实现写法有多种,但是并不都...

  • Spring知识点持续更新......

    Spring框架中的单例Beans是线程安全的吗?Spring框架并没有对单例bean进行任务的多线程封装处理。关...

  • Java单例模式

    转载: 你真的会写单例模式吗-------Java实现 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想...

网友评论

      本文标题:你写的单例一定安全吗?

      本文链接:https://www.haomeiwen.com/subject/fezqgftx.html