如何防止JAVA反射对单例类的攻击?

Posted luquanjian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何防止JAVA反射对单例类的攻击?相关的知识,希望对你有一定的参考价值。

加静态标志位,构造方法通过synchronized修饰。或者枚举

举例1:不经过处理的单例类被JAVA反射机制攻击

Singleton.java    代码清单【1.1】

技术图片
 1 public class Singleton 
 2 {
 3     private static boolean flag = true;
 4     private static final Singleton INSTANCE = new Singleton();
 5     
 6     private Singleton()
 7     {
 8     }
 9     
10     public static Singleton newInstance()
11     {
12         return INSTANCE;
13     }
14 
15 }
技术图片

 

SingletonReflectAttack.java  代码清单【1.2】

技术图片
 1 /**
 2      * 单例模式被java反射攻击
 3      * @throws IllegalArgumentException
 4      * @throws InstantiationException
 5      * @throws IllegalAccessException
 6      * @throws InvocationTargetException
 7      * @throws SecurityException
 8      * @throws NoSuchMethodException
 9      */
10     
11     public static void attack() throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException
12     {
13         Class<?> classType = Singleton.class;
14         Constructor<?> constructor = classType.getDeclaredConstructor(null);
15         constructor.setAccessible(true);
16         Singleton singleton = (Singleton) constructor.newInstance();
17         Singleton singleton2 = Singleton.newInstance();
18         System.out.println(singleton == singleton2);  //false
19     }
技术图片

 

测试结果:SingletonReflectAttackMain.java  代码清单【1.3】

技术图片
 1 /**
 2      * 1.测试单例模式被java反射攻击
 3      * @throws NoSuchMethodException 
 4      * @throws InvocationTargetException 
 5      * @throws IllegalAccessException 
 6      * @throws InstantiationException 
 7      * @throws SecurityException 
 8      * @throws IllegalArgumentException 
 9      */
10     @Test
11     public void testSingletonReflectAttack() throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
12     {
13         System.out.println("-------------单例模式被java反射攻击测试--------------");
14         SingletonReflectAttack.attack();
15         System.out.println("--------------------------------------------------");
16     }
17     
技术图片

 

运行结果:

技术图片

  返回结果为false,说明创建了两个不同的实例。通过反射获取构造函数,然后调用setAccessible(true)就可以调用私有的构造函数;所以创建出来的两个实例时不同的对象。

如果要抵御这种攻击,就要修改构造器,让他在被要求创建第二个实例的时候抛出异常。

下面,我们对饿汉式单例模式做修改。

举例2.经过处理的单例类,JAVA反射机制攻击测试

SingletonNotAttackByReflect.java   代码清单【2.1】

技术图片
 1 package com.lxf.singleton;
 2 
 3 import javax.management.RuntimeErrorException;
 4 
 5 public class SingletonNotAttackByReflect
 6 {
 7     private static boolean flag = false;
 8     private static final SingletonNotAttackByReflect INSTANCE = new SingletonNotAttackByReflect();
 9     
10     //保证其不被java反射攻击
11     private SingletonNotAttackByReflect()
12     {
13         synchronized (SingletonNotAttackByReflect.class) 
14         {
15             if(false == flag)
16             {
17                 flag = !flag;
18             }
19             else
20             {
21                 throw new RuntimeException("单例模式正在被攻击");
22             }
23             
24         }
25     }
26     
27     public static SingletonNotAttackByReflect getInstance()
28     {
29         return INSTANCE;
30     }
31 
32     
33 }
技术图片

 

 SingletonReflectAttack.java  代码清单【2.2】

技术图片
 1 public static void modifiedByAttack() 
 2     {
 3         try 
 4         {
 5             Class<SingletonNotAttackByReflect> classType = SingletonNotAttackByReflect.class;
 6             Constructor<SingletonNotAttackByReflect> constructor = classType.getDeclaredConstructor(null);
 7             constructor.setAccessible(true);
 8             SingletonNotAttackByReflect singleton = (SingletonNotAttackByReflect) constructor.newInstance();
 9             SingletonNotAttackByReflect singleton2 = SingletonNotAttackByReflect.getInstance();
10             
11             System.out.println(singleton == singleton2); 
12         } 
13         catch (Exception e)
14         {
15             e.printStackTrace();
16         }
17         
18     }
技术图片

 

SingletonReflectAttackMain.java  代码清单【2.3】

技术图片
 1 /**
 2      * 2.修改后的单例模式被java反射攻击测试.
 3      * 攻击失败
 4      * @throws IllegalArgumentException
 5      * @throws SecurityException
 6      * @throws InstantiationException
 7      * @throws IllegalAccessException
 8      * @throws InvocationTargetException
 9      * @throws NoSuchMethodException
10      */
11     
12     @Test
13     public void testModifiedByattack() throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
14     {
15         System.out.println("-------------修改后的单例模式被java反射攻击测试--------------");
16         SingletonReflectAttack.modifiedByAttack();
17         System.out.println("----------------------------------------------------------");
18     }
技术图片

 

运行结果:

技术图片

技术图片

在之前,我们也介绍过,枚举类型的单例模式也可以防止被JAVA反射攻击,这里我们简单测试一下。

举例3:枚举类型的单例模式被JAVA反射机制攻击测试

Singleton6.java    代码清单【3.1】

技术图片
 1 public enum Singleton6
 2 {
 3     INSTANCE;
 4     
 5     private Resource instance;
 6     
 7     Singleton6()
 8     {
 9         instance = new Resource();
10     }
11     
12     public Resource getInstance()
13     {
14         return instance;
15     }
16     
17     
18 }
技术图片

 

 

 SingletonReflectAttack.java  代码清单【3.2】

技术图片
 1     public static void enumAttack() throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException
 2     {
 3         try 
 4         {
 5             Class<Singleton6> classType = Singleton6.class;
 6             Constructor<Singleton6> constructor =(Constructor<Singleton6>) classType.getDeclaredConstructor();
 7             constructor.setAccessible(true);
 8             constructor.newInstance();
 9             
10         } 
11         catch (Exception e) 
12         {
13             e.printStackTrace();
14         }
技术图片

 

SingletonReflectAttackMain.java  代码清单【3.3】

技术图片
 1 /**
 2      * 枚举类型的单例模式被java反射攻击测试
 3      * 攻击失败
 4      * 
 5      * @throws IllegalArgumentException
 6      * @throws SecurityException
 7      * @throws InstantiationException
 8      * @throws IllegalAccessException
 9      * @throws InvocationTargetException
10      * @throws NoSuchMethodException
11      */
12     
13     @Test
14     public void testenumAttack() throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
15     {
16         System.out.println("-------------枚举类型的单例模式被java反射攻击测试--------------");
17         SingletonReflectAttack.enumAttack();
18         System.out.println("----------------------------------------------------------");
19     }
技术图片

 

运行结果:

技术图片

 

原文:https://www.cnblogs.com/lthIU/p/6240128.html

以上是关于如何防止JAVA反射对单例类的攻击?的主要内容,如果未能解决你的问题,请参考以下文章

双重检查锁实现单例(java)

单例模式如何防止反射攻击

java单例类的几种实现

super allocWithZone 对单例类概念有一些疑问

如何实现单例模式

单例类的总结