我写的程序员面试系列
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程序员面试和笔试准备的书籍,作者为何昊。本书可能包含了大量关于Java编程语言的基础知识、高级特性以及与面试相关的技巧和策略等内容。下面将对可能涉及的重要...
Java单例模式是一种最简单的创建型设计模式,主要用于对系统资源的管理与控制。在软件开发中大量使用,如Windows的文件系统、回收站、打印机等。 单例模式有三个特点: 1. 单例类只能有一个实例; 2. 必须自行创建...
Java程序员面试是每个Java开发者职业生涯中的重要环节,它既是检验技术实力的方式,也是展示个人学习能力和解决问题能力的舞台。本文将深入探讨Java程序员面试中涉及的一些核心知识点,旨在帮助求职者更好地准备面试...
2018java程序员面试宝典+题库,很全。压缩的文档,打开是PDF版
《Java程序员面试笔试宝典》是一本专门为寻求Java相关职位的程序员准备的参考资料,它涵盖了Java编程语言的基础、进阶以及面试中常见的问题和考点。这本书的高清版旨在提供清晰易读的学习体验,帮助读者更好地理解和...
java中级程序员面试题 java程序员面试题 java工程师面试题
Java程序员面试大全,这是一份综合性的资源,涵盖了Java程序员在面试和笔试过程中可能遇到的各种问题和知识点。作为Java开发者,深入理解并掌握这些内容至关重要,因为它们将直接影响到你在技术领域的竞争力和职业...
Java程序员面试宝典是每一位Java开发者在准备晋升或求职时不可或缺的参考资料。这份宝典涵盖了Java高级工程师面试的各个方面,旨在帮助应聘者全面理解和掌握Java技术栈的核心概念、最佳实践以及实际问题解决能力。...
单例设计模式是软件开发中一种重要的设计模式,它的核心思想是确保一个类只有一个实例...总的来说,单例模式在控制对象生命周期、优化资源使用和简化系统结构方面都有显著作用,是Java程序员应掌握的重要设计模式之一。
Singleton文档则专门讨论了单例模式,它是Java中最常见的设计模式之一,面试者需理解其作用、实现方式以及线程安全问题。 4. **Model2-Oracle&JDBC&Hibernate-test.doc & Model2-Oracle&JDBC&Hibernate-answer.doc...
首先,标题"java程序员面试简历 WORD 模版"表明这是一个专门为Java程序员设计的Word文档模板,用于构建面试简历。在制作简历时,你需要关注以下几点: 1. **个人信息**:简历的开头应包含姓名、联系方式(电话、...
Java程序员面试宝典是每一位Java开发者在准备面试时不可或缺的参考资料。这份PDF文件包含了122道精心挑选的Java面试题目,旨在全面覆盖Java编程语言的核心概念、框架、设计模式以及最佳实践。以下是对这份宝典中可能...
java程序员面试宝典.chm;讲了java面试的许多东西,要面试的同志可以看下了。
Java作为世界上最受欢迎的编程语言之一,其程序员面试通常会涉及到以下几个核心知识点: 1. **基础语法**:面试者需要熟悉Java的基本语法,包括数据类型、变量、运算符、流程控制(if语句、switch语句、循环)、...
java程序员面试简历模板java程序员面试简历模板java程序员面试简历模板java程序员面试简历模板java程序员面试简历模板
Java程序员在面试和笔试过程中,会遇到各种各样的问题,这些问题涵盖了Java语言的基础、进阶、多线程、网络编程、数据库操作、设计模式、框架应用等多个方面。本篇文章将根据提供的资料,深入探讨其中的一些关键知识...