博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(单例设计模式之一)饿汉式的反射与反序列化漏洞
阅读量:5049 次
发布时间:2019-06-12

本文共 2443 字,大约阅读时间需要 8 分钟。

1.闲话少说,直接上代码。

import java.io.Serializable;

//饿汉式
public class Singleton01 implements Serializable{
    //1.私有的属性
    private static Singleton01 instance=new Singleton01();
    //2.私有的构造器
    private Singleton01(){}
    //3.共有的get()方法
    public static  Singleton01 getInstance(){//这里不需要加同步块synchronized
        return instance;
    }
}

为什么不需要加同步块?这里插播一条短消息

1.  饿汉式是天然的线程安全的,因此不需要加线程锁。饿汉式之所以是天然的线程安全,是因为:

一个字节码文件被加载到内存会经历以下过程:

1、链接(1、验证2、准备3、解析)

2、初始化

3、使用

4、卸载

初始化是执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译器自动收集类中的所有类变量的赋 值动作和静态语句块(static)中的语句合并产生的。在这个过程中instance已经被实例化了。并且虚拟机JVM会保证一个类 的<clinit>()方法在多线程的环境中被正确加锁和同步。因此他是天然线程安全的。

 

2.下面代码分析如何使用反射破解懒汉式:

public class Singletons_Test_02 {

    public static void main(String[] args) throws Exception {

   Class<Singleton01> clazz = (Class<Singleton01>) Class.forName("com.shc.singleton.Singleton01");

        Constructor<Singleton01> c = clazz.getDeclaredConstructor(null);//获得无参构造器
        c.setAccessible(true);//跳过权限检查,访问私有的构造器
        Singleton01 s3 = c.newInstance();
        Singleton01 s4 = c.newInstance();
        System.out.println(s3);
        System.out.println(s4);

  }

}

此时输出s3与s4的哈希值是相等的。代表不是同一个对象,饿汉式单例通过反射破解完成。

3.下面分析饿汉式如何避免反射漏洞?

public class Singleton1 {

    //1.私有的属性
    private static Singleton1 instance=new Singleton1();
    //2.私有的构造器
    private Singleton1(){
        if (null != instance) {
            throw new RuntimeException();
        }
    }
    //3.共有的get()方法
    public static  Singleton1 getInstance(){//天然的线程安全,不需要加同步块,因此调用效率高
        return instance;
    }
}

在私有的构造器中加一个判断,判断要创建的对象是否存在,如果不存在再创建,已存在就抛出运行时异常。

4.下面利用序列化与反序列化漏洞破解饿汉式单例

public class Singletons_Test_03 {

    public static void main(String[] args) throws Exception {

    Singleton01 s1 = Singleton01.getInstance();

        Singleton01 s2 = Singleton01.getInstance();
        System.out.println(s1);
        System.out.println(s2);
        
        //序列化
        FileOutputStream fos = new FileOutputStream("../a.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(s1);
        oos.close();
        fos.close();
        
        //反序列化
         ObjectInputStream ois =new ObjectInputStream(new FileInputStream("../a.txt"));
         Singleton01 s3 = (Singleton01) ois.readObject();
         System.out.println(s3);

  }

}

5.破解饿汉式反序列化漏洞

public class Singleton11 implements Serializable{

    //1.私有的属性
    private static Singleton11 instance=new Singleton11();
    //2.私有的构造器
    private Singleton11(){}
    //3.共有的get()方法
    public static Singleton11 getInstance(){
        return instance;
    }
    //反序列化时(加这个方法可以防止反序列化漏洞)
    private Object readResolve() throws ObjectStreamException{
        return instance;
    }
}

以上demo较为简单,不做深入研究,设计模式体验重在应用。

转载于:https://www.cnblogs.com/Model-frog/p/5641619.html

你可能感兴趣的文章
css3动画属性
查看>>
第九次团队作业-测试报告与用户使用手册
查看>>
Equal Sides Of An Array
查看>>
CentOS笔记-用户和用户组管理
查看>>
Mongodb 基本命令
查看>>
Qt中QTableView中加入Check列实现
查看>>
“富豪相亲大会”究竟迷失了什么?
查看>>
控制文件的备份与恢复
查看>>
返回代码hdu 2054 A==B?
查看>>
Flink独立集群1
查看>>
iOS 8 地图
查看>>
20165235 第八周课下补做
查看>>
[leetcode] 1. Two Sum
查看>>
iOS 日常工作之常用宏定义大全
查看>>
PHP的SQL注入技术实现以及预防措施
查看>>
MVC Razor
查看>>
软件目录结构规范
查看>>
Windbg调试Sql Server 进程
查看>>
linux调度器系列
查看>>
mysqladmin
查看>>