1. 程式人生 > >利用反射機制破壞單例(2)

利用反射機制破壞單例(2)

前言

在部落格上看到一篇《防止單例模式被JAVA反射攻擊》的文章,通過一個靜態布林變數記錄下單例類是否是第一次初始化,然後在建構函式內丟擲異常來防止反射破壞。看起來合情合理,但細想,通過反射來修改那個靜態變數,再呼叫建構函式進行例項化,同樣可以破壞。按照上面的原理,我換了另一種方式實現單例類,並進行破壞。下面進行程式碼演示。

程式碼實現

單例類:

public class SingletonProPro {
    private static SingletonProPro instance;
    private SingletonProPro(){
        if
(instance!=null){ throw new RuntimeException("單例類已攔截入侵"); } } public static SingletonProPro getInstance(){ if(instance==null){ synchronized(SingletonProPro.class){ if(instance==null){ instance=new SingletonProPro(); } } } return
instance; } }

攻擊程式碼:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class Main {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        //通過呼叫getSingleton()方式獲取物件
SingletonProPro instance1 = SingletonProPro.getInstance(); //通過反射方式獲取物件 Class singletonProClass = instance1.getClass(); SingletonProPro instance2 = null; //修改instance為null Field flag = singletonProClass.getDeclaredField("instance"); flag.setAccessible(true); System.out.println(flag.get(instance1)); flag.set(instance1,null); System.out.println(flag.get(instance1)); Constructor<?> constructor = singletonProClass.getDeclaredConstructor();//獲取當前Class所表示類中指定的一個的構造器,和訪問許可權無關 constructor.setAccessible(true); //設定私有方法的可訪問(切記,這裡必須設定,否則會丟擲下圖的異常) instance2 = (SingletonProPro) constructor.newInstance(); if(instance1==instance2){ System.out.println("相等"); }else { System.out.println("不相等"); } } }

輸出結果:

[email protected]14ae5a5
null
不相等

防止反射破壞單例

最簡單的方法就是用static final來修飾instance並初始化:

public class SingletonPro {
    private static final SingletonPro instance = new SingletonPro();
     private SingletonPro(){
         if(instance!=null){
             throw new RuntimeException("單例模式被侵犯!");
         }
     }
     public static SingletonPro getInstance(){
         return instance;
     }
}