zoukankan      html  css  js  c++  java
  • 单例模式防止反射和反序列化漏洞

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

    public static void main(String[] args) throws Exception {
            SingletonDemo1 sc1 = SingletonDemo1.getInstance();
            SingletonDemo1 sc2 = SingletonDemo1.getInstance();
            System.out.println(sc1); // sc1,sc2是同一个对象
            System.out.println(sc2);
    
            // 通过反射的方式直接调用私有构造器(通过在构造器里抛出异常可以解决此漏洞)
    //      Class<SingletonDemo1> clazz = (Class<SingletonDemo1>) Class.forName("com.sankuai.ia.demo.web.service.SingletonDemo1");
    //        Constructor<SingletonDemo1> c = clazz.getDeclaredConstructor(null);
    //        c.setAccessible(true); // 跳过权限检查
    //        SingletonDemo1 sc3 = c.newInstance();
    //        SingletonDemo1 sc4 = c.newInstance();
    //        System.out.println(sc3);  // sc3,sc4不是同一个对象
    //        System.out.println(sc4);
    
            // 通过反序列化的方式构造多个对象(类需要实现Serializable接口)
    
            // 1. 把对象sc1写入硬盘文件
            FileOutputStream fos = new FileOutputStream("object.out");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(sc1);
            oos.close();
            fos.close();
    
            // 2. 把硬盘文件上的对象读出来
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.out"));
            // 如果对象定义了readResolve()方法,readObject()会调用readResolve()方法。从而解决反序列化的漏洞
            SingletonDemo1 sc5 = (SingletonDemo1) ois.readObject();
            // 反序列化出来的对象,和原对象,不是同一个对象。如果对象定义了readResolve()方法,可以解决此问题。
            System.out.println(sc5);
            ois.close();
        }

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

    package com.sankuai.ia.demo.web.service;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.ObjectStreamException;
    import java.io.Serializable;
    import java.lang.reflect.Constructor;
    
    /**
     *
     *
     *  静态内部类实现方式(也是一种懒加载方式)
     *  这种方式:线程安全,调用效率高,并且实现了延迟加载
     *  解决反射和反序列化漏洞
     *
     **/
    public class SingletonDemo2 implements Serializable{
    
            private static class SingletonClassInstance {
                private static final SingletonDemo2 instance = new SingletonDemo2();
            }
    
            // 方法没有同步,调用效率高
            public static SingletonDemo2 getInstance() {
                return SingletonClassInstance.instance;
            }
    
            // 防止反射获取多个对象的漏洞
            private SingletonDemo2() {
                if (null != SingletonClassInstance.instance)
                    throw new RuntimeException();
            }
    
            // 防止反序列化获取多个对象的漏洞
            private Object readResolve() throws ObjectStreamException {
                return SingletonClassInstance.instance;
            }
    
        public static void main(String[] args) throws Exception {
            SingletonDemo2 sc1 = SingletonDemo2.getInstance();
            SingletonDemo2 sc2 = SingletonDemo2.getInstance();
            System.out.println(sc1); // sc1,sc2是同一个对象
            System.out.println(sc2);
    
            // 通过反射的方式直接调用私有构造器(通过在构造器里抛出异常可以解决此漏洞)
            Class<SingletonDemo2> clazz = (Class<SingletonDemo2>) Class.forName("com.sankuai.ia.demo.web.service.SingletonDemo2");
            Constructor<SingletonDemo2> c = clazz.getDeclaredConstructor(null);
            c.setAccessible(true); // 跳过权限检查
            SingletonDemo2 sc3 = c.newInstance();
            SingletonDemo2 sc4 = c.newInstance();
            System.out.println("通过反射的方式获取的对象sc3:" + sc3);  // sc3,sc4不是同一个对象
            System.out.println("通过反射的方式获取的对象sc4:" + sc4);
    
            // 通过反序列化的方式构造多个对象(类需要实现Serializable接口)
    
            // 1. 把对象sc1写入硬盘文件
            FileOutputStream fos = new FileOutputStream("object.out");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(sc1);
            oos.close();
            fos.close();
    
            // 2. 把硬盘文件上的对象读出来
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.out"));
            // 如果对象定义了readResolve()方法,readObject()会调用readResolve()方法。从而解决反序列化的漏洞
            SingletonDemo2 sc5 = (SingletonDemo2) ois.readObject();
            // 反序列化出来的对象,和原对象,不是同一个对象。如果对象定义了readResolve()方法,可以解决此问题。
            System.out.println("对象定义了readResolve()方法,通过反序列化得到的对象:" + sc5);
            ois.close();
        }
    }
  • 相关阅读:
    assembly 基础
    自定义编写0号内中断除法错误的中断处理程序
    Codeforces Round #573 (Div. 2) D. Tokitsukaze, CSL and Stone Game (博弈,思维)
    Codeforces Round #573 (Div. 2) E. Tokitsukaze and Duel (博弈)
    Schedule HDU
    牛客假日团队赛5 F 随机数 BZOJ 1662: [Usaco2006 Nov]Round Numbers 圆环数 (dfs记忆化搜索的数位DP)
    洛谷 P2866 [USACO06NOV]糟糕的一天Bad Hair Day 牛客假日团队赛5 A (单调栈)
    「BZOJ1669」D 饥饿的牛 [Usaco2006 Oct] Hungry Cows 牛客假日团队赛5 (LIS,离散化树状数组)
    树状数组求LIS模板
    牛客OI周赛11-普及组 B Game with numbers (数学,预处理真因子)
  • 原文地址:https://www.cnblogs.com/cjn123/p/12159536.html
Copyright © 2011-2022 走看看