我写的程序员面试系列
Java面试系列-webapp文件夹和WebContent文件夹的区别?
程序员面试系列:Spring MVC能响应HTTP请求的原因?
Java程序员面试系列-什么是Java Marker Interface(标记接口)
JavaScript面试系列:JavaScript设计模式之桥接模式和懒加载
使用JavaScript ES6的新特性计算Fibonacci(非波拉契数列)
单例模式在很多Java程序员的眼中,应该是设计模式里最简单的一种了。那么单例模式可能会被攻击,您听说过么?
说到“单例模式被攻击”这个话题,大家最容易想到的可能就是通过序列化/反序列化来攻击单例模式,因为一个对象实例序列化再反序列化后,得到的新的对象虽然各字段内容和原字段一致,然而对象地址和原始对象地址相比已经发生了变化,因此它们是两个不同的对象。
上面的结论完全正确,然而除了序列化/反序列化,单例模式还可能遭受另一种方式的攻击,即反射攻击(Reflection attack)。
看一个具体例子:
public class JerrySingleton {
private String name;
private JerrySingleton(){
name = "Jerry";
}
private static class SingletonHolder{
private static final JerrySingleton INSTANCE = new JerrySingleton();
}
public static JerrySingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
上面是一个饿汉式单例。
然而我只需要将这个单例类JerrySingleton的构造函数通过反射设置成可以访问Accessible,然后就能通过反射调用该构造函数,进而生成新的对象实例。这样就破坏了单例模式。
Class<?> classType = JerrySingleton.class;
Constructor<?> c = classType.getDeclaredConstructor(null);
c.setAccessible(true);
JerrySingleton e1 = (JerrySingleton)c.newInstance();
JerrySingleton e2 = JerrySingleton.getInstance();
System.out.println(e1 == e2);
第6行代码会打印false。
针对这种攻击,一种可行的防御措施是在单例类的构造函数内定义一个布尔变量,初始化为false。当构造函数执行后,该变量被置为true。如果接下来构造函数再次被执行,则人为抛出异常,避免构造函数重复执行。
public class JerrySingletonImproved {
private static boolean flag = false;
private JerrySingletonImproved(){
synchronized(JerrySingletonImproved.class) {
if(flag == false) {
flag = !flag;
}
else {
throw new RuntimeException("Singleton violated");
}
}
}
}
这种防御措施无法从根本上杜绝Singleton被攻击,因为攻击者仍旧可以通过反射来修改布尔变量flag的值,从而绕过这个检查。
最理想的不会受到攻击的单例模式实现是借助Java里枚举类Enumeration的特性:
这种实现类型的单例模式的消费代码:
System.out.println("Name:" + JerrySingletonAnotherApproach.INSTANCE.getName());
如果攻击者通过前面介绍的反射代码对这种实现方式的单例进行攻击,JDK会抛出NoSuchMethodException异常:
Exception in thread "main" java.lang.NoSuchMethodException: singleton.JerrySingletonAnotherApproach.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at singleton.SingletonAttack.test3(SingletonAttack.java:31)
at singleton.SingletonAttack.main(SingletonAttack.java:43)
究其原因,是因为现在我们是通过Java枚举方式实现的单例,枚举类没有传统意义上的构造函数,因此对这种反射攻击免疫。
要获取更多Jerry的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:
相关推荐
java程序员面试交流项目经验java程序员面试交流项目经验java程序员面试交流项目经验java程序员面试交流项目经验java程序员面试交流项目经验java程序员面试交流项目经验java程序员面试交流项目经验java程序员面试交流...
Java程序员面试资料及简历模版 Java程序员面试资料及简历模版 Java程序员面试资料及简历模版 Java程序员面试资料及简历模版 Java程序员面试资料及简历模版 Java程序员面试资料及简历模版 Java程序员面试资料及简历...
详细分析了应聘Java程序员职位的常见考点,主要内容包括面试流程及求职准备、Java语言基础、数据类型、集合框架、图形用户界面、输入与输出、多线程、反射机制、网络编程、JDBC、Web开发基础、SSH框架(Struts、...
Java程序员面试笔试宝典-何昊pdf版,高清,带有书签。
Java程序员面试Java程序员面试Java程序员面试Java程序员面试Java程序员面试Java程序员面试
JAVA程序员面试 JAVA程序员面试 JAVA程序员面试 JAVA程序员面试
java程序员面试题java程序员面试题java程序员面试题java程序员面试题java程序员面试题java程序员面试题
Java程序员面试宝典2011最新出炉Java程序员面试宝典2011最新出炉Java程序员面试宝典2011最新出炉Java程序员面试宝典2011最新出炉Java程序员面试宝典2011最新出炉Java程序员面试宝典2011最新出炉Java程序员面试宝典...
2018年最新版Java程序员面试宝典,面试的神器,可以有效的通过面试环节,得到满意的工作
java程序员面试指南(代码 java程序员面试指南(代码 java程序员面试指南(代码 java程序员面试指南(代码 java程序员面试指南(代码
2018java程序员面试宝典+题库,很全。压缩的文档,打开是PDF版
Java程序员面试宝典,Java程序员面试宝典PDF文件。122道Java面试题及详细解答。希望可以对您有所帮助。
java中级程序员面试题 java程序员面试题 java工程师面试题
Java程序员面试宝典,Java高级工程师面试宝典,Java面试题大全
Java程序员面试宝典.pdfJava程序员面试宝典.pdfJava程序员面试宝典.pdfJava程序员面试宝典.pdf
java程序员面试宝典.chm;讲了java面试的许多东西,要面试的同志可以看下了。
java程序员面试必备的32个要点java程序员面试必备的32个要点java程序员面试必备的32个要点java程序员面试必备的32个要点java程序员面试必备的32个要点java程序员面试必备的32个要点java程序员面试必备的32个要点java...
程序员面试宝典:变态级Java程序员面试32问
Java程序员面试题集(1-50),共50道题目,都是面试java程序员必备的题目,有答案和详细解释