单例模式如何防止反射攻击
Posted 猿猿HHH
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式如何防止反射攻击相关的知识,希望对你有一定的参考价值。
单例模式例子:
public class Single {
private Single () {//私有化构造方法
}
private static volatile Single instance = null;
public static synchronized Single getInstance() {
if(instance==null){
instance = new Single();//在此方法内创建对象
}
return instance;//返回所创建的对象
}
}
以上代码若采用反射来创建对象就会翻车了!!
例子:
class Main{
public static void main(String[] args) throws Exception {
Class clazz = Single.class;
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Single single = Single.getInstance();
Single single1 = (Single) constructor.newInstance();
System.out.println(single==single1);
}
}
输出:
这方法如何解决呢?
暴力反射调取了类中的私有化构造器方法,而instance属性是静态的,所以可以判断instance是否为null,若不是null,则抛出异常警告
代码如下:
public class Single {
private Single () {
if(instance!=null){
throw new RuntimeException("禁止使用反射调用!");
}
}
private static volatile Single instance = null;
public static synchronized Single getInstance() {
if(instance==null){
instance = new Single();
}
return instance;
}
}
运行结果如下:
成功解决!
在这读者可能会有个问题,以上只使用了一次反射来调取构造方法创建对象,若两次创建对象都采用反射的方式呢?该如何解决?
例如
class Main{
public static void main(String[] args) throws Exception {
Class clazz = Single.class;
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Single single1 = (Single) constructor.newInstance();
Single single = (Single) constructor.newInstance();
System.out.println(single==single1);
}
}
很遗憾,这种情况下若要坚持采用懒汉式的单例模式是不能解决的。
只能够使用饿汉式的单例模式解决:
public class Single {
private Single () {
if(instance!=null){
throw new RuntimeException("禁止使用反射调用!");
}
}
private static volatile Single instance = new Single();
public static Single getInstance() {
// if(instance==null){
// instance = new Single();
// }
return instance;
}
}
class Main{
public static void main(String[] args) throws Exception {
// Single single1 = Single.getInstance();
// Single single2 = Single.getInstance();
// System.out.println(single1==single2);
Class clazz = Single.class;
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
// Single single = Single.getInstance();
Single single1 = (Single) constructor.newInstance();
Single single = (Single) constructor.newInstance();
System.out.println(single==single1);
}
}
以上是关于单例模式如何防止反射攻击的主要内容,如果未能解决你的问题,请参考以下文章