CSDNfastjson到底做错了什么?为什么会被频繁爆出漏洞?


CSDNfastjson到底做错了什么?为什么会被频繁爆出漏洞?
本文插图
fastjson大家一定都不陌生 , 这是阿里巴巴的开源一个JSON解析库 , 通常被用于将Java Bean和JSON 字符串之间进行转换 。
前段时间 , fastjson被爆出过多次存在漏洞 , 很多文章报道了这件事儿 , 并且给出了升级建议 。
但是作为一个开发者 , 我更关注的是他为什么会频繁被爆漏洞?于是我带着疑惑 , 去看了下fastjson的releaseNote以及部分源代码 。
最终发现 , 这其实和fastjson中的一个AutoType特性有关 。
从2019年7月份发布的v1.2.59一直到2020年6月份发布的 v1.2.71, 每个版本的升级中都有关于AutoType的升级 。
下面是fastjson的官方releaseNotes 中 , 几次关于AutoType的重要升级:
1.2.59发布 , 增强AutoType打开时的安全性 fastjson
1.2.60发布 , 增加了AutoType黑名单 , 修复拒绝服务安全问题 fastjson
1.2.61发布 , 增加AutoType安全黑名单 fastjson
1.2.62发布 , 增加AutoType黑名单、增强日期反序列化和JSONPath fastjson
1.2.66发布 , Bug修复安全加固 , 并且做安全加固 , 补充了AutoType黑名单 fastjson
1.2.67发布 , Bug修复安全加固 , 补充了AutoType黑名单 fastjson
1.2.68发布 , 支持GEOJSON , 补充了AutoType黑名单 。 (引入一个safeMode的配置 , 配置safeMode后 , 无论白名单和黑名单 , 都不支持autoType 。 ) fastjson
1.2.69发布 , 修复新发现高危AutoType开关绕过安全漏洞 , 补充了AutoType黑名单 fastjson
1.2.70发布 , 提升兼容性 , 补充了AutoType黑名单
甚至在fastjson的开源库中 , 有一个Isuue是建议作者提供不带autoType的版本:


CSDNfastjson到底做错了什么?为什么会被频繁爆出漏洞?
本文插图
那么 , 什么是AutoType?为什么fastjson要引入AutoType?为什么AutoType会导致安全漏洞呢?本文就来深入分析一下 。
AutoType 何方神圣?fastjson的主要功能就是将Java Bean序列化成JSON字符串 , 这样得到字符串之后就可以通过数据库等方式进行持久化了 。 但是 , fastjson在序列化以及反序列化的过程中并没有使用Java自带的序列化机制 , 而是自定义了一套机制 。 其实 , 对于JSON框架来说 , 想要把一个Java对象转换成字符串 , 可以有两种选择:
  • 1、基于属性
  • 2、基于setter/getter
而我们所常用的JSON序列化框架中 , FastJson和jackson在把对象序列化成json字符串的时候 , 是通过遍历出该类中的所有getter方法进行的 。 Gson并不是这么做的 , 他是通过反射遍历该类中的所有属性 , 并把其值序列化成json 。 假设我们有以下一个Java类:class Store {private String name;private Fruit fruit;public String getName {return name;}public void setName(String name) {this.name = name;}public Fruit getFruit {return fruit;}public void setFruit(Fruit fruit) {this.fruit = fruit;}}interface Fruit {}class Apple implements Fruit {private BigDecimal price;//省略 setter/getter、toString等}当我们要对他进行序列化的时候 , fastjson会扫描其中的getter方法 , 即找到getName和getFruit , 这时候就会将name和fruit两个字段的值序列化到JSON字符串中 。 那么问题来了 , 我们上面的定义的Fruit只是一个接口 , 序列化的时候fastjson能够把属性值正确序列化出来吗?如果可以的话 , 那么反序列化的时候 , fastjson会把这个fruit反序列化成什么类型呢?我们尝试着验证一下 , 基于(fastjson v 1.2.68):Store store = new Store;store.setName("Hollis");Apple apple = new Apple;apple.setPrice(new BigDecimal(0.5));store.setFruit(apple);String jsonString = JSON.toJSONString(store);System.out.println("toJSONString : " + jsonString);以上代码比较简单 , 我们创建了一个store , 为他指定了名称 , 并且创建了一个Fruit的子类型Apple , 然后将这个store使用


推荐阅读