反射和反序列化破解单例模式以及解决方案

本文探讨了如何使用反射和反序列化方法破解单例模式,并提供了相应的解决方案。通过修改构造器以防止反射攻击,以及在反序列化时添加额外代码来避免对象重复创建,可以有效保护单例模式的完整性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 *  反射和反序列化可以破解除了枚举之外的4种实现方式。

反射破解单例:

        TestDcl dcl1 = TestDcl.getInstance();
        TestDcl dcl2 = TestDcl.getInstance();
        System.out.println(dcl1);
        System.out.println(dcl2);
        //反射破解单例  两个不一样
        Class<TestDcl> c = (Class<TestDcl>) Class.forName("cn.oyh.thread.TestDcl");
        Constructor<TestDcl> con =c.getDeclaredConstructor();
        con.setAccessible(true);
        TestDcl dcl3 = con.newInstance();
        TestDcl dcl4 = con.newInstance();
        System.out.println(dcl3);
        System.out.println(dcl4);

上面的TestDcl在这里可以找到,执行:

cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@677327b6
cn.oyh.thread.TestDcl@14ae5a5

会发现后面两个反射创建的对象和上面两个都不相同,单例模式是对外只有一个对象。那么怎么破解呢?很简单:

 //1.构造器私有化
    private TestDcl(){
     // 防止反射创建多个对象:多次调用抛出异常,创建不成功
        if(instance !=null){
            throw new RuntimeException();
        }
    }

在构造器这改下代码就行了,在执行,会抛出异常。

反序列化破解单例:

也就是把单例模式反序列化,那么需要实现Serializable接口:

public class TestDcl implements Serializable{
        TestDcl dcl1 = TestDcl.getInstance();
        TestDcl dcl2 = TestDcl.getInstance();
        System.out.println(dcl1);
        System.out.println(dcl2);
        //通过反序列化构造多个对象破解单例:需要实现Serializable接口
        FileOutputStream fos = new FileOutputStream("src/copy.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(dcl1);
        oos.close();
        fos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/copy.txt"));
        TestDcl dcl3 = (TestDcl) ois.readObject();
        System.out.println(dcl3);

执行:

cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@3b9a45b3

反序列化的和上面不同,不是一个对象,怎么破解?在TestDcl类里添加一段代码即可:

  /*
    破解反序列化创建多个对象:
    在反序列化时,如果定义了readResovle(),那么就直接返回那个对象,
    而不需要创建新的对象。
     */
    private Object readResolve() throws ObjectStreamException{
        return instance;
    }

执行:

cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@1540e19d

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值