美文网首页
反射的破坏性

反射的破坏性

作者: taojian | 来源:发表于2018-07-05 16:47 被阅读0次

如何防止反射破坏单例?

参考:https://www.jianshu.com/p/5f529f18821a
基于单例模式,有很多实现方法,如:饿汉,懒汉。但是大多只会考虑到单实例和线程安全的问题,很少会考虑到反射对其的破坏。

由于反射这种Bug一样的存在,可以在系统任意地方实例化出一个对象。

//饿汉单例模式
public class Singleton {
    private static Singleton instance = new Singleton();  
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        return instance;
    }
}

//通过反射破坏单例模式
public class Test {
    public static void main(String[] args) throws Exception{
        Singleton s1 = Singleton.getInstance();
 
        Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton s2 = constructor.newInstance();
 
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
 
    }
}

反射可以直接调用构造函数,哪怕是私有的。

唯一的方法就是:
1.保证构造函数Singleton()只能别调用一次,这个才是关键。
2.利用好静态变量,因为静态变量有且只有一个,这个是JVM保证的。

public class Singleton {
    private static int count = 0;

    private static Singleton instance = null; 

    private Singleton(){
        synchronized (Singleton.class) {
            if(count > 0){
                throw new RuntimeException("创建了两个实例");
            }
            count++;
        }

    }

    public static Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

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

        Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton s1 = constructor.newInstance();
        Singleton s2 = constructor.newInstance();
    }

}

1.同步语句块synchronized()保证线程安全的生成实例
2.静态变量count保证唯一可靠,用来判断实例是否已经新增

扩展: 通过Java的序列化破坏单例

大概的思路就是:把实例对象写进任意文件中,然后读取出来构造新的对象

参考:https://www.jianshu.com/p/56c9bbcf0832

@Test
public  void test() throws Exception{
        SingletonDemo6 nomarlInstance1 = SingletonDemo6.getInstance();
        
    //把对象写入文件
        File file = new File("/xxx/xxx/xxx/xxx/xxx/SingletonDemo/a.txt");
        FileOutputStream fos = new FileOutputStream(file);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(nomarlInstance1);
        oos.close();
        fos.close();
        
        //序列化把对象读取
        FileInputStream fis = new FileInputStream(file);
        ObjectInputStream ois = new ObjectInputStream(fis);
        SingletonDemo6 serilizeInstance = (SingletonDemo6) ois.readObject();
        
        System.out.println(nomarlInstance1);
        System.out.println(serilizeInstance);
}

序列化破坏就三个步骤:
1.获得单例对象
2.对象写进文件
3.文件流反序列化为对象(实际上利用了字节码Class)

1我们阻止不了,2我们也阻止不了,只能寄希望于3。

//JVM中反序列化得语句
ois.readObject();

//源码,转诶object的时候调用readOrdinaryObject方法
case TC_OBJECT:
 return checkResolve(readOrdinaryObject(unshared));

//readOrdinaryObject方法里面直接调用了invokeReadResolve,看意思应该是要调用某个方法
Object rep = desc.invokeReadResolve(obj);

//里面真的调用了一个方法readResolveMethod,readResolveMethod是成员变量
return readResolveMethod.invoke(obj, (Object[]) null);

//点进去看看,这个成员变量指向了对象的readResolve方法
readResolveMethod = getInheritableMethod(
                        cl, "readResolve", null, Object.class);

so,应该是反序列化的时候调用了对象的readResolve做到的。
为了防止被反序列化,那我们就自己重写readResolve方法,让反序列化返回原本的单例对象!!!

private Object readResolve() throws ObjectStreamException{
     return SingletonDemo6.s1;
}

当然上述操作,具体怎么做还是的看你是饿汉还是懒汉。

目前来讲,从单例可靠性来说,比较好的方法是:

饿汉:
  1.直接使用饿汉式+重写readResolve
  2.直接使用枚举(自带线程安全和无法序列化新的枚举)
懒汉:
  1.匿名内部类+重写readResolve

如何防止反射调用私有方法?

大家一致会以为,private是私有不允许访问的,但是在反射看来都不是事。

那有没有方法防止呢?
没有!

java中有个配置叫SecurityManager,通过对jvm的配置来启用安全策略,然后在反射时进行权限检查。

上述的话未经过验证,但是哪怕是有设置,依然可以通过启动java的参数去做更改,如:java -jar xxx.jar -Dspring.server.port:8888。只要是参数,都没有命令行的级别高,因此只要有人有权限,根本没办法从根本上防止反射调用私有方法。

总结

说了那么多防止!防止!防止!
其实为什么要防止,安全性?
同为开发,真要破坏根本防不了,还需要那么曲折吗?
实际上的安全性,指的是对外,比如hash攻击,密钥被破解这些。

反射的创建不是让你去各种各样的防止这个那个。
更多的是提供了一种可能:

1.提供一种可能: 让你封装类型动态的方法;
2.提供一种可能: 对原有设计错误的补救;

相关文章

  • 反射的破坏性

    如何防止反射破坏单例? 参考:https://www.jianshu.com/p/5f529f18821a基于单例...

  • 【家庭干预】破坏性行为

    第四章 破坏性行为 * 破坏性行为,也许是治疗过程中遇到的最大障碍之一 * 最大的障碍,也许不是破坏性行为本身,而...

  • 【日更484】书摘:你的善良,也许只是软弱

    1.破坏性是可以被转化的,当攻击性背后的渴望被看见时,转化就会发生,破坏性会变成创造性。看见就是转化破坏性的灵丹妙...

  • Java基础之反射

    Java基础之反射 反射基本介绍 反射的使用通过反射调用属性和方法通过反射获取配置文件 反射基本介绍 Java反射...

  • Java反射与joor反射库的使用

    java原生反射的使用 反射构造对象 反射方法 反射字段 joor反射库的使用 github:https://gi...

  • 《儿童纪律教育》学习感悟

    八幼 尚丽娜 一、关注儿童的破坏性行为 幼儿时期孩子有时候的会出现一些破坏性行...

  • Java互联网公司-经典面试题附答案

    基础:Java 反射?反射有什么缺点?你是怎么理解反射的(为什么框架需要反射)?优点:反射具有解耦性,缺点:反射属...

  • Java反射

    什么是反射? 反射的作用? 反射性能优化?

  • 情绪的破坏性

    周天吃完早饭冠州要玩枕头大战,因为州爸去加油了,我怕打起来场面失控伤着瀚中,又想到他昨天嗨了一整天没练琴,于...

  • 2020年必学的3个JavaScript框架

    React React并不是最早的基于JavaScript的破坏性Web框架之一。但这是最具破坏性和影响力的基于J...

网友评论

      本文标题:反射的破坏性

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