程序员面试系列之Java单例模式的攻击与防御
我写的程序员面试系列
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单例模式的攻击与防御的更多相关文章
- 寻找下一个结点 牛客网 程序员面试金典 C++ java Python
寻找下一个结点 牛客网 程序员面试金典 C++ java Python 题目描述 请设计一个算法,寻找二叉树中指定结点的下一个结点(即中序遍历的后继). 给定树的根结点指针TreeNode* root ...
- 碰撞的蚂蚁 牛客网 程序员面试金典 C++ Java Python
碰撞的蚂蚁 牛客网 程序员面试金典 C++ Java Python 题目描述 在n个顶点的多边形上有n只蚂蚁,这些蚂蚁同时开始沿着多边形的边爬行,请求出这些蚂蚁相撞的概率.(这里的相撞是指存在任意两只 ...
- 检查是否是BST 牛客网 程序员面试金典 C++ java Python
检查是否是BST 牛客网 程序员面试金典 C++ java Python 题目描述 请实现一个函数,检查一棵二叉树是否为二叉查找树. 给定树的根结点指针TreeNode* root,请返回一个boo ...
- Java程序员面试宝典1 ---Java基础部分(该博文为原创,转载请注明出处)
(该博文为原创,转载请注明出处 http://www.cnblogs.com/luyijoy/ by白手伊凡) 1. 基本概念 1) Java为解释性语言,运行过程:程序源 ...
- java程序员面试宝典之——Java 基础部分(1~10)
基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io 的语法,虚拟机方面的语法. 1.一个".java"源文件中是否可以包 ...
- JAVA程序员面试宝典
程序员面试之葵花宝典 面向对象的特征有哪些方面 1. 抽象:抽象就是忽略一个主题中与当前目标2. 无关的那些方面,3. 以便更充分地注意与当前目标4. 有关的方面.抽象并不5. 打算了解全部问题 ...
- Java程序员面试之葵花宝典
程序员面试之葵花宝典 1.面向对象的特征有哪些方面 抽象:抽象就是忽略一个主题中与当前目标 无关的那些方面, 以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而 只是选择其中的一部 ...
- 两年Java程序员面试经验分享,从简历制作到面试总结!
前言 工作两年左右,实习一年左右,正式工作一年左右,其实挺尴尬的,高不成低不就.因此在面试许多公司,找到了目前最适合自己的公司之后.于是做一个关于面试的总结.希望能够给那些依旧在找工作的同学提供帮助. ...
- 《JAVA 程序员面试宝典(第四版)》读书笔记之前言
工作五年了一直在小的软件公司混,总感觉自己的专业知识没有太大的提升.当然了中间也换了一两家公司,面试的公司就很多家,总感觉正规的软件公司(无论大小)对于基础知识的考核都非常重视,而不管你说你之前服务过 ...
随机推荐
- AutoIt脚本在做自动化操作的时候,如何进行错误捕获?
我的自动化脚本在运行的时候,会生成一个界面,点击该页面上的按钮能够进行自动化操作. 经常遇到的一个问题是: 脚本运行一半,GUI程序出现了异常情况,这个时候,再次点击生成的界面上的按钮,不会有任何反应 ...
- 多线程-threading模块2
从上面例子中发现线程的创建是颇为麻烦的,每创建一个线程都需要创建一个 t(t1.t2....),如果创建的线程较多时这样极其不方便.下面对通过例子进行改进: #coding:utf-8 impor ...
- Babel转码器
Babel是一个广泛使用的ES6转码器,可以将ES6代码转为ES5代码,从而在现有环境执行.这意味着,你可以用ES6的方法 编写程序,又不用担心现在环境是否支持.
- 字符指针unsigned char *ch_p
指向类型为unsigned char的指针变量叫字符指针. 例如: unsigned char ch = 'a'; unsigned char *ch_p = &ch;那么指针变量ch_p就是 ...
- js获取动态日期时间
var timer=null; function tt(n){ if(n<10){ return '0'+n }else{ return n+'' } } timer=setInterval(f ...
- CF 8D two friends
独立想的好开心呀(然而是一道水题). 可以看出这道题的答案是满足单调性的,然后可以考虑二分. 对于当前二分出的mid值,我们考虑这个过程. 假设他们能共同走到shop然后共同会home $$Ans = ...
- 清理c盘的文件
C:/Users/用户名/AppData里面默认有三个文件夹,分别是Local,LocalLow,Roaming,简单地来说,都是用来存放软件的配置文件和临时文件的,里面有很多以软件公司或者软件名称命 ...
- python __builtins__ zip类 (71)
71.'zip' , 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表.如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作 ...
- bzoj 1176 [Balkan2007]Mokia 【CDQ分治】
W过大,很难在线维护,考虑离线算法 给每个操作加一个时间属性n,显然,对于n=i的询问,对它有影响的修改只在n<i中,所以可以CDQ(因为是按时间序读进来的,所以不用排序了 对于统计矩形和,可以 ...
- PJzhang:漏洞渗透测试框架“天使之剑(AngelSword)”
猫宁!!! 参考链接: www.phpinfo.cc/?post=42 https://www.freebuf.com/sectool/149883.html 同事介绍了一款渗透测试框架AngelSw ...