在我的上篇随笔中,我们知道了创建单例类有以下几种方式:

  (1).饿汉式;

  (2).懒汉式(、加同步锁的懒汉式、加双重校验锁的懒汉式、防止指令重排优化的懒汉式);

  (3).登记式单例模式;

  (4).静态内部类单例模式;

  (5).枚举类型的单例模式。

在上面的5种实现方式中,除了枚举类型外,其他的实现方式是可以被JAVA的反射机制给攻击的,即使他的构造方法是私有化的,我们也可以做一下处理,从外部得到它的实例。

  下面,我将会举例来说明:

说明:

  Singleton.java     没有经过处理的饿汉式单例模式实现方式

  Singleton6.java   枚举类型的单例模式

  SingletonNotAttackByReflect.java         经过处理的饿汉式单例模式实现方式

  SingletonReflectAttack.java    具体反射类

  SingletonReflectAttackMain.java    JUnit测试类

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

Singleton.java    代码清单【1.1】

 public class Singleton
{
private static boolean flag = true;
private static final Singleton INSTANCE = new Singleton(); private Singleton()
{
} public static Singleton newInstance()
{
return INSTANCE;
} }

SingletonReflectAttack.java  代码清单【1.2】

 /**
* 单例模式被java反射攻击
* @throws IllegalArgumentException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws SecurityException
* @throws NoSuchMethodException
*/ public static void attack() throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException
{
Class<?> classType = Singleton.class;
Constructor<?> constructor = classType.getDeclaredConstructor(null);
constructor.setAccessible(true);
Singleton singleton = (Singleton) constructor.newInstance();
Singleton singleton2 = Singleton.newInstance();
System.out.println(singleton == singleton2); //false
}

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

 /**
* 1.测试单例模式被java反射攻击
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws SecurityException
* @throws IllegalArgumentException
*/
@Test
public void testSingletonReflectAttack() throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
System.out.println("-------------单例模式被java反射攻击测试--------------");
SingletonReflectAttack.attack();
System.out.println("--------------------------------------------------");
}

运行结果:

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

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

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

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

SingletonNotAttackByReflect.java   代码清单【2.1】

 package com.lxf.singleton;

 import javax.management.RuntimeErrorException;

 public class SingletonNotAttackByReflect
{
private static boolean flag = false;
private static final SingletonNotAttackByReflect INSTANCE = new SingletonNotAttackByReflect(); //保证其不被java反射攻击
private SingletonNotAttackByReflect()
{
synchronized (SingletonNotAttackByReflect.class)
{
if(false == flag)
{
flag = !flag;
}
else
{
throw new RuntimeException("单例模式正在被攻击");
} }
} public static SingletonNotAttackByReflect getInstance()
{
return INSTANCE;
} }

SingletonReflectAttack.java  代码清单【2.2】

 public static void modifiedByAttack()
{
try
{
Class<SingletonNotAttackByReflect> classType = SingletonNotAttackByReflect.class;
Constructor<SingletonNotAttackByReflect> constructor = classType.getDeclaredConstructor(null);
constructor.setAccessible(true);
SingletonNotAttackByReflect singleton = (SingletonNotAttackByReflect) constructor.newInstance();
SingletonNotAttackByReflect singleton2 = SingletonNotAttackByReflect.getInstance(); System.out.println(singleton == singleton2);
}
catch (Exception e)
{
e.printStackTrace();
} }

SingletonReflectAttackMain.java  代码清单【2.3】

 /**
* 2.修改后的单例模式被java反射攻击测试.
* 攻击失败
* @throws IllegalArgumentException
* @throws SecurityException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws NoSuchMethodException
*/ @Test
public void testModifiedByattack() throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
System.out.println("-------------修改后的单例模式被java反射攻击测试--------------");
SingletonReflectAttack.modifiedByAttack();
System.out.println("----------------------------------------------------------");
}

运行结果:

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

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

Singleton6.java    代码清单【3.1】

 public enum Singleton6
{
INSTANCE; private Resource instance; Singleton6()
{
instance = new Resource();
} public Resource getInstance()
{
return instance;
} }

SingletonReflectAttack.java  代码清单【3.2】

     public static void enumAttack() throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException
{
try
{
Class<Singleton6> classType = Singleton6.class;
Constructor<Singleton6> constructor =(Constructor<Singleton6>) classType.getDeclaredConstructor();
constructor.setAccessible(true);
constructor.newInstance(); }
catch (Exception e)
{
e.printStackTrace();
}

SingletonReflectAttackMain.java  代码清单【3.3】

 /**
* 枚举类型的单例模式被java反射攻击测试
* 攻击失败
*
* @throws IllegalArgumentException
* @throws SecurityException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws NoSuchMethodException
*/ @Test
public void testenumAttack() throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
System.out.println("-------------枚举类型的单例模式被java反射攻击测试--------------");
SingletonReflectAttack.enumAttack();
System.out.println("----------------------------------------------------------");
}

运行结果:

4.总结与拓展

所以,在项目开发中,我们要根据实际情况,选择最安全的单例模式实现方式。

如何防止JAVA反射对单例类的攻击?的更多相关文章

  1. 设计模式(java) 单例模式 单例类

    ·单例类 单实例类,就是这个类只能创建一个对象,保证了对象实例的唯一性. 1.单例模式( Singleton Pattern) 是一个比较简单的模式, 其定义如下:Ensure a class has ...

  2. 用 Java 写一个单例类?

    饿汉式单例 public class Singleton { private Singleton(){} private static Singleton instance = new Singlet ...

  3. 《Effective Java》 读书笔记(三) 使用私有构造方法或枚举实现单例类

    1.单例类到现在为止算是比较熟悉的一种设计模式了,最开始写单例模式是在C#里面,想要自己实现一个单例类,代码如下: public class Instance { private static rea ...

  4. Java中Class和单例类的作用与类成员的理解

    Java中Class类的作用与深入理解 在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识.这个信息跟踪着每个对象所属的类.JVM利用运行时信息选择相应的方法执行.而保存 ...

  5. java单例类/

    java单例类  一个类只能创建一个实例,那么这个类就是一个单例类 可以重写toString方法 输出想要输出的内容 可以重写equcal来比较想要比较的内容是否相等 对于final修饰的成员变量 一 ...

  6. 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类

    static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...

  7. Java单例类的简单实现

    对于java新手来说,单例类给我的印象挺深,之前一道web后台笔试题就是写单例类.*.*可惜当时不了解. 在大部分时候,我们将类的构造器定义成public访问权限,允许任何类自由创建该类的对象.但在某 ...

  8. [Android面试题-7] 写出一个Java的Singleton类(即单例类)

    1.首先明确单例的概念和特点: a>单例类只能有一个实例 b>单例类必须自己创建一个自己的唯一实例 c>单例类必须为其他所有对象提供这个实例 2.单例具有几种模式,最简单的两种分别是 ...

  9. java单例类的几种实现

    一,最简单的方式 public class Singleton{ private Singleton(){}; private static Singleton instance = new Sing ...

随机推荐

  1. 如何在Flex标签中写事件函数

    在事件变量值中直接写函数语句,如果是多条语句,则用";"号隔开. 示例如下: <mx:Box id="label" backgroundColor=&qu ...

  2. 56992 vuser_init.c(12): Error: Socket descriptor not found.

    Loadrunner 运行场景时提示" vuser_init.c(12): Error: Socket descriptor not found.  Hint: the problem mi ...

  3. 循序渐进Python3(十一) --1-- web之css

    css样式: css是英文Cascading Style Sheets的缩写,称为层叠样式表,用于对页面进行美化,CSS的可以使页面更加的美观. 基本上所有的html页面都或多或少的使用css.   ...

  4. matlab图

    .6 统计作图 4.6.1 正整数的频率表 命令 正整数的频率表 函数 tabulate 格式 table = tabulate(X) %X为正整数构成的向量,返回3列:第1列中包含X的值第2列为这些 ...

  5. Angularjs学习笔记(一)

    大部分传统的模板系统,对模板的渲染是个线性单向的过程:模板或变量与模板混合在一起产生结果的标记集合.任何对模型的改变都需要通过模板的重新计算.但AngularJS有所不同,任何用户引发的视图的改变,都 ...

  6. hdu5452 Minimum Cut

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5452 题意:给你一个图和它的生成树,要你在树上删一条边,问你最少删多少条边使得图不联通(开始时图一定联 ...

  7. 关于 The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine. 异常处理

    导入Excel在本地环境没有问题,但部署到服务器上后出现异常. 经排查,是系统问题,因为本地是32位系统,而服务器上则是64位系统. 解决方法: 1.打开IIS管理器 2.右击应用程序所在的连接池 3 ...

  8. 【BZOJ3123】森林(主席树,启发式合并)

    题意:一个带点权的森林,要求维护以下操作: 1.询问路径上的点权K大值 2.两点之间连边 n,m<=80000 思路:如果树的结构不发生变化只需要维护DFS序 现在因为树的结构发生变化,要将两棵 ...

  9. jquery选择器 之 获取父级元素、同级元素、子元素

    jquery选择器 之 获取父级元素.同级元素.子元素 一.获取父级元素 1. parent([expr]): 获取指定元素的所有父级元素 <div id="par_div" ...

  10. maven 编译项目时:报com.sun.image.codec.jpeg不存在

    项目中用到图片处理相关的一些工具类,在eclipse开发工具内,程序并没有什么问题,都可以正常使用,项目也没有报错,但通过maven 进行编译打包时,则会报错: 程序包com.sun.image.co ...