Java设计模式(一):单例模式,防止反射和反序列化漏洞

http://blog.csdn.net/hardwin/article/details/51477359

一、懒汉式单例模式,解决反射和反序列化漏洞

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.iter.devbox.singleton;  
  2.   
  3. import java.io.ObjectStreamException;  
  4. import java.io.Serializable;  
  5.   
  6. /** 
  7.  * 懒汉式(如何防止反射和反序列化漏洞) 
  8.  * @author Shearer 
  9.  * 
  10.  */  
  11. public class SingletonDemo6 implements Serializable{  
  12.       
  13.     // 类初始化时,不初始化这个对象(延迟加载,真正用的时候再创建)  
  14.     private static SingletonDemo6 instance;  
  15.       
  16.     private SingletonDemo6() {  
  17.         // 防止反射获取多个对象的漏洞  
  18.         if (null != instance) {  
  19.             throw new RuntimeException();  
  20.         }  
  21.     }  
  22.       
  23.     // 方法同步,调用效率低  
  24.     public static synchronized SingletonDemo6 getInstance() {  
  25.         if (null == instance)  
  26.             instance = new SingletonDemo6();  
  27.         return instance;  
  28.     }  
  29.   
  30.     // 防止反序列化获取多个对象的漏洞。  
  31.     // 无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。  
  32.     // 实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。  
  33.     private Object readResolve() throws ObjectStreamException {    
  34.         return instance;  
  35.     }  
  36. }  
  37.   
  38.   
  39. package com.iter.devbox.singleton;  
  40.   
  41. import java.io.FileInputStream;  
  42. import java.io.FileOutputStream;  
  43. import java.io.ObjectInputStream;  
  44. import java.io.ObjectOutputStream;  
  45.   
  46. public class Client2 {  
  47.   
  48.     public static void main(String[] args) throws Exception {  
  49.         SingletonDemo6 sc1 = SingletonDemo6.getInstance();  
  50.         SingletonDemo6 sc2 = SingletonDemo6.getInstance();  
  51.         System.out.println(sc1); // sc1,sc2是同一个对象  
  52.         System.out.println(sc2);  
  53.           
  54.         // 通过反射的方式直接调用私有构造器(通过在构造器里抛出异常可以解决此漏洞)  
  55. /*      Class<SingletonDemo6> clazz = (Class<SingletonDemo6>) Class.forName("com.iter.devbox.singleton.SingletonDemo6"); 
  56.         Constructor<SingletonDemo6> c = clazz.getDeclaredConstructor(null); 
  57.         c.setAccessible(true); // 跳过权限检查 
  58.         SingletonDemo6 sc3 = c.newInstance(); 
  59.         SingletonDemo6 sc4 = c.newInstance(); 
  60.         System.out.println(sc3);  // sc3,sc4不是同一个对象 
  61.         System.out.println(sc4);*/  
  62.           
  63.         // 通过反序列化的方式构造多个对象(类需要实现Serializable接口)  
  64.           
  65.         // 1. 把对象sc1写入硬盘文件  
  66.         FileOutputStream fos = new FileOutputStream("object.out");  
  67.         ObjectOutputStream oos = new ObjectOutputStream(fos);  
  68.         oos.writeObject(sc1);  
  69.         oos.close();  
  70.         fos.close();  
  71.           
  72.         // 2. 把硬盘文件上的对象读出来  
  73.         ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.out"));  
  74.         // 如果对象定义了readResolve()方法,readObject()会调用readResolve()方法。从而解决反序列化的漏洞  
  75.         SingletonDemo6 sc5 = (SingletonDemo6) ois.readObject();  
  76.         // 反序列化出来的对象,和原对象,不是同一个对象。如果对象定义了readResolve()方法,可以解决此问题。  
  77.         System.out.println(sc5);   
  78.         ois.close();  
  79.     }  
  80.   
  81. }  


二、静态内部类式单例模式(解决反射和反序列化漏洞)

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.iter.devbox.singleton;  
  2.   
  3. import java.io.ObjectStreamException;  
  4. import java.io.Serializable;  
  5.   
  6. /** 
  7.  * 静态内部类实现方式(也是一种懒加载方式) 
  8.  * 这种方式:线程安全,调用效率高,并且实现了延迟加载 
  9.  * 解决反射和反序列化漏洞 
  10.  * @author Shearer 
  11.  * 
  12.  */  
  13. public class SingletonDemo7 implements Serializable{  
  14.       
  15.     private static class SingletonClassInstance {  
  16.         private static final SingletonDemo7 instance = new SingletonDemo7();  
  17.     }  
  18.       
  19.     // 方法没有同步,调用效率高  
  20.     public static SingletonDemo7 getInstance() {  
  21.         return SingletonClassInstance.instance;  
  22.     }  
  23.       
  24.     // 防止反射获取多个对象的漏洞  
  25.     private SingletonDemo7() {  
  26.         if (null != SingletonClassInstance.instance)  
  27.             throw new RuntimeException();  
  28.     }  
  29.       
  30.     // 防止反序列化获取多个对象的漏洞  
  31.     private Object readResolve() throws ObjectStreamException {    
  32.         return SingletonClassInstance.instance;  
  33.     }  
  34. }  
  35.   
  36.   
  37. package com.iter.devbox.singleton;  
  38.   
  39. import java.io.FileInputStream;  
  40. import java.io.FileOutputStream;  
  41. import java.io.ObjectInputStream;  
  42. import java.io.ObjectOutputStream;  
  43. import java.lang.reflect.Constructor;  
  44.   
  45. public class Client3 {  
  46.   
  47.     public static void main(String[] args) throws Exception {  
  48.         SingletonDemo7 sc1 = SingletonDemo7.getInstance();  
  49.         SingletonDemo7 sc2 = SingletonDemo7.getInstance();  
  50.         System.out.println(sc1); // sc1,sc2是同一个对象  
  51.         System.out.println(sc2);  
  52.           
  53.         // 通过反射的方式直接调用私有构造器(通过在构造器里抛出异常可以解决此漏洞)  
  54.         Class<SingletonDemo7> clazz = (Class<SingletonDemo7>) Class.forName("com.iter.devbox.singleton.SingletonDemo7");  
  55.         Constructor<SingletonDemo7> c = clazz.getDeclaredConstructor(null);  
  56.         c.setAccessible(true); // 跳过权限检查  
  57.         SingletonDemo7 sc3 = c.newInstance();  
  58.         SingletonDemo7 sc4 = c.newInstance();  
  59.         System.out.println("通过反射的方式获取的对象sc3:" + sc3);  // sc3,sc4不是同一个对象  
  60.         System.out.println("通过反射的方式获取的对象sc4:" + sc4);  
  61.           
  62.         // 通过反序列化的方式构造多个对象(类需要实现Serializable接口)  
  63.           
  64.         // 1. 把对象sc1写入硬盘文件  
  65.         FileOutputStream fos = new FileOutputStream("object.out");  
  66.         ObjectOutputStream oos = new ObjectOutputStream(fos);  
  67.         oos.writeObject(sc1);  
  68.         oos.close();  
  69.         fos.close();  
  70.           
  71.         // 2. 把硬盘文件上的对象读出来  
  72.         ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.out"));  
  73.         // 如果对象定义了readResolve()方法,readObject()会调用readResolve()方法。从而解决反序列化的漏洞  
  74.         SingletonDemo7 sc5 = (SingletonDemo7) ois.readObject();  
  75.         // 反序列化出来的对象,和原对象,不是同一个对象。如果对象定义了readResolve()方法,可以解决此问题。  
  76.         System.out.println("对象定义了readResolve()方法,通过反序列化得到的对象:" + sc5);   
  77.         ois.close();  
  78.     }  
  79.   
  80. }  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值