博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
程序员面试系列之Java单例模式的攻击与防御
阅读量:6704 次
发布时间:2019-06-25

本文共 2080 字,大约阅读时间需要 6 分钟。

我写的程序员面试系列

单例模式在很多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.
()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的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:

转载地址:http://xdblo.baihongyu.com/

你可能感兴趣的文章
《UNIX/Linux网络日志分析与流量监控》新书上市一个月,销量位列畅销榜 TOP 10...
查看>>
我的友情链接
查看>>
上课笔记分享-1-第17课时-1-多域名-统一沟通-环境
查看>>
网络传输数据格式的选择
查看>>
shell脚本:查看KVM虚拟机中的网卡信息(不需要进入启动或进入虚拟机)
查看>>
Python老司机也会翻车!10个最容易犯的Python开发错误
查看>>
SSL,TLS协议与OpenSSL "心血"heartbleed漏洞之伤
查看>>
手机网民超PC,淘金移动互联网正当时
查看>>
零基础学习Puppet自动化配置管理(文档持续更新中)
查看>>
我的家庭私有云计划-21
查看>>
用graphite把收集到的数据渲染成图片
查看>>
Objective-C中的@class,SEL和IMP等灵活机制
查看>>
手抖删掉mysql的生产库,一定要跑路么?
查看>>
Microsoft UC 2013 Preview-3-Deploy Microsoft SharePoint Server 2013
查看>>
老鸟经验谈linux运维人员到底要不要考linux认证
查看>>
《iPhone与iPad开发实战—iOS经典应用剖析》连载三
查看>>
烂泥:如何更换Facebook头像
查看>>
马哥团队带你揭秘互联网巨头公司—阿里巴巴
查看>>
如何形成高端战力
查看>>
演示:使用NBAR统计与分析流量
查看>>