FastJson反序列化后,子类类型转换问题及解决办法

FastJson反序列化后,子类类型转换问题及解决办法

1. 问题描述

  • 使用FastJson序列化的时候,如果用于序列化的对象中将子类用父类类型保存进去,在反序列化的之后,将对象中该子类对象取出,如果强转为子类类型,就会抛出类型转换异常
  • 在使用String类型报文或者json字符串传输的系统中,该问题会比较常见

2. 问题重现

  • 问题代码
  1. 调用类
public class FastJsonIssue {
    public static void main(String[] args) {
        new FastJsonIssue().test();
    }

    public void test() {
        List<Fruit> fruits = new ArrayList<>();
        // 可以看到Apple类作为Fruit的子类,将其放入List<Fruit>中
        fruits.add(new Apple(10));
        // 将List<Fruit>放入BuyFruits类中
        BuyFruits buyFruits = new BuyFruits(new BigDecimal(10), fruits);
        // 将BuyFruits类对象序列化为json字符串的过程
        String json = JSON.toJSONString(buyFruits);
        // 模拟收到报文并将其反序列化为buyFruitsResult对象
        BuyFruits buyFruitsResult = JSON.parseObject(json, BuyFruits.class);
        // 从BuyFruits中取出List<Fruit>
        List<Fruit> fruits1 = buyFruitsResult.getFruits();
        // 将之前存入集合的Apple类对象取出,并强转成Apple类型,报类型转换错误
        Apple apple = (Apple) fruits1.get(0);
    }

}
  1. 相关类
/**
 * BuyFruits类,里面存有父类Fruit类的List
 * @author August_Z
 */
public class BuyFruits implements Serializable {
    private BigDecimal price;
    private List<Fruit> fruits;

    public BuyFruits(BigDecimal price, List<Fruit> fruits) {
        this.price = price;
        this.fruits = fruits;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public List<Fruit> getFruits() {
        return fruits;
    }

    public void setFruits(List<Fruit> fruits) {
        this.fruits = fruits;
    }

}

/**
 * 水果类,是各种具体水果类的父类
 * @author August_Z
 */
public class Fruit implements Serializable {
    private int amount;

    public Fruit(int amount) {
        this.amount = amount;
    }

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }
}

/**
 * 苹果类,是水果类的子类
 * @author August_Z
 */
public class Apple extends Fruit implements Serializable {

    public Apple(int amount) {
        super(amount);
    }

}
  • 报错信息
  1. 报错信息为类型转换异常,显然子类信息在经过FastJson的序列化和反序列化之后,并没有得到保留
java.lang.ClassCastException: com.forms.lego.sysm.bfs.Fruit cannot be cast to com.forms.lego.sysm.bfs.Apple
  1. 进一步查看源码可以发现,反序列过程中,FastJson只能通过BuyFruits.class获取到相应Fruit类信息,并进行相应的反序列化,并不能获取到存入的子类信息,以至于反序列化之后的只有Fruit对象,强转之后抛出类型转换异常

3. 解决方案

  • 方案描述

    实际生产中可以将该对象通过IO流转化为byte[]再通过FastJson转换为json字符串,在使用时先将json字符串转换为byte[],再通过IO流转化为JavaBean对象, 可以发现子类信息依然保留,不会出现类型转换异常信息。

  • 代码实施
public class FastJsonIssue {
    public static void main(String[] args) {
        new FastJsonIssue().test();
    }

    public void test() {
        List<Fruit> fruits = new ArrayList<>();
        // 可以看到Apple类作为Fruit的子类,将其放入List<Fruit>中
        fruits.add(new Apple(10));
        // 将List<Fruit>放入BuyFruits类中
        BuyFruits buyFruits = new BuyFruits(new BigDecimal(10), fruits);
        // 通过工具类将BuyFruits类对象转换为byte[]
        byte[] bytes = ObjectAndByteUtils.toByteArray(buyFruits);
        // 用FastJson将byte[]序列化为json字符串
        String json = JSON.toJSONString(bytes);
        // 模拟收到报文并将其反序列化成byte[]
        byte[] bytesResult = JSON.parseObject(json,byte[].class);
        // 使用用具类将byte[]转换为Object再强转为BuyFruits类对象
        BuyFruits buyFruitsResult = (BuyFruits)ObjectAndByteUtils.toObject(bytesResult);
        // 从BuyFruits中取出List<Fruit>
        List<Fruit> fruits1 = buyFruitsResult.getFruits();
        // 可以看到通过io转换之后再使用FastJson序列化不会有异常抛出
        Apple apple = (Apple) fruits1.get(0);
    }
}

/**
 * Object和byte[]互相转换类
 *
 * @author August_Z
 * @date 2020/7/20 19:32
 */
public class ObjectAndByteUtils {
    /**
     * 对象转数组
     *
     * @param obj 传入对象
     * @return byte[]数组
     */
    public static byte[] toByteArray(Object obj) {
        byte[] bytes = null;
        ByteArrayOutputStream bos =null;
        ObjectOutputStream oos=null;
        try {
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bytes = bos.toByteArray();
        } catch (IOException ex) {
            ex.printStackTrace();
        }finally {
            try {
                if (oos != null) {
                    oos.close();
                }
                if (bos != null) {
                    bos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bytes;
    }

    /**
     * 数组转对象
     *
     * @param bytes byte数组
     * @return 响应对象
     */
    public static Object toObject(byte[] bytes) {
        Object obj = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            bis = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bis);
            obj = ois.readObject();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (ois != null) {
                    ois.close();
                }
                if (bis != null) {
                    bis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return obj;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Fastjson是一款Java语言编写的高性能JSON处理器,被广泛应用于各种Java应用程序中。然而,Fastjson存在反序列化漏洞,黑客可以利用该漏洞实现远程代码执行,因此该漏洞被广泛利用。 检测Fastjson反序列化漏洞的方法: 1. 扫描源代码,搜索是否存在Fastjson相关的反序列化代码,如果存在,则需要仔细检查反序列化的过程是否安全。 2. 使用工具进行扫描:目前市面上有很多漏洞扫描工具已经支持Fastjson反序列化漏洞的检测,例如:AWVS、Nessus、Burp Suite等。 利用Fastjson反序列化漏洞的方法: 1. 利用Fastjson反序列化漏洞执行远程命令:黑客可以构造一个恶意JSON字符串,通过Fastjson反序列化漏洞实现远程命令执行。 2. 利用Fastjson反序列化漏洞实现文件读取:黑客可以构造一个恶意JSON字符串,通过Fastjson反序列化漏洞实现文件读取操作。 3. 利用Fastjson反序列化漏洞实现反弹Shell:黑客可以构造一个恶意JSON字符串,通过Fastjson反序列化漏洞实现反弹Shell操作。 防范Fastjson反序列化漏洞的方法: 1. 更新Fastjson版本:Fastjson官方在1.2.46版本中修复了反序列化漏洞,建议使用该版本或更高版本。 2. 禁止使用Fastjson反序列化:如果应用程序中不需要使用Fastjson反序列化功能,建议禁止使用该功能,可以使用其他JSON处理器。 3. 输入验证:对所有输入进行校验和过滤,确保输入数据符合预期,避免恶意数据进入系统。 4. 序列化过滤:对敏感数据进行序列化过滤,确保敏感数据不会被序列化。 5. 安全加固:对系统进行安全加固,如限制系统权限、加强访问控制等,避免黑客利用Fastjson反序列化漏洞获取系统权限。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值