文档章节

fastjson漏洞导致服务瘫痪,先别忙升级

zxiaofan666
 zxiaofan666
发布于 10/13 21:30
字数 1532
阅读 2018
收藏 10

1、背景

  2019年9月5日,fastjson修复了当字符串中包含\x转义字符时可能引发OOM的问题。建议广大用户升级fastjson版本至少到1.2.60。
  一个bug这么恐怖,竟然直接OOM,亲身体验下吧。测试代码如下:

JSON.parse("[{\"a\":\"a\\x]");

实验效果:4分钟 堆内存 占用上升达2G;

fastjson_x_oom

  这么牛掰,甲方爸爸高度重视,火速把自己负责的服务的fastjson版本升级到1.2.60,线上运行也相安无事。

  如果这就结束了,本文也就不用写了。⊙﹏⊙‖∣

2、fastjson升级后业务异常

  fastjson升级几天后,一老系统业务发生异常,异常信息如下:

Exception in thread "xxx" com.alibaba.fastjson.JSONException: expect ':' at 0, actual =
	at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:290)
	at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1380)
	at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1346)
	at com.alibaba.fastjson.JSON.parse(JSON.java:156)
	at com.alibaba.fastjson.JSON.parse(JSON.java:166)
	at com.alibaba.fastjson.JSON.parse(JSON.java:135)
	at com.alibaba.fastjson.JSON.parseObject(JSON.java:227)
	at alibaba.fastjson.FastJsonBug.main(FastJsonBug.java:70)

  看这错误,肯定是json字符串格式有误,应该是冒号的地方实际上是等号了,然后导致反序列化异常,果断排查接口入参,结果入参一切正常。纳尼。。。
  好吧,那就本地debug吧,结果竟然在本地复现异常了,震惊!!!再次检查接口入参,没有问题,和以前正常运行的入参是一致的。想到最近升级fastjson了,还原fastjson版本试试吧。还原后还真是正常了!!!

  难道fastjson版本升级出了大bug?

黑人问号

  本着对阿里技术的信任,我决定一探究竟。

3、一探究竟

  待反序列化的数据,其格式是2层List嵌套,测试代码已做脱敏处理(完整源码见后文github地址):

String json = "{\"bvos\":[{\"names\":[\"zxiaofan\"]}]}";
JSONObject jsonObjectB1 = GSON.fromJson(json, JSONObject.class);
JSONArray jsonArrayB = jsonObjectB1.getJSONArray("bvos");
JSONObject jsonObjectB2 = JSONObject.parseObject(jsonArrayB.get(0).toString());
// 上面这行代码直接异常了,异常信息如下:
// com.alibaba.fastjson.JSONException: expect ':' at 0, actual =

  好奇宝宝们就不要纠结于为什么没有定义好实体再使用TypeReference一步到位啦,千年老代码确实是这样的,这也不是本文的重点。
  经过debug发现,jsonArrayB.get(0).toString()的值是 {names=[zxiaofan]}。注意了,names后面是等号,不是冒号,这也就能解释为什么异常是“expect ':' at 0, actual =”了。
  但为什么升级后就异常,没升级就一切正常呢?继续研究下,梳理后发现如下值得注意的地方:

  • 1、fastjson版本时1.2.54时正常,大于1.2.54后便会异常;
  • 2、运行代码是Google的Gson和阿里的fastjson混用的(json处理全部换成fastjson一切正常);

  莫非,是fastjson升级后和Google的Gson不兼容导致?

仿佛看到了曙光。

看到了曙光

  对比分析了fastjson 1.2.54版本和其之后的版本(以下以1.2.55版本为例),发现getJSONArray(String key)还真有区别。

//  fastjson <version>1.2.54</version>

    public JSONArray getJSONArray(String key) {
        Object value = this.map.get(key);
        if (value instanceof JSONArray) {
            return (JSONArray)value;
        } else {
            return value instanceof String ? (JSONArray)JSON.parse((String)value) : (JSONArray)toJSON(value);
        }
    }
//  fastjson <version>1.2.55</version>

    public JSONArray getJSONArray(String key) {
        Object value = this.map.get(key);
        if (value instanceof JSONArray) {
            return (JSONArray)value;
        } else if (value instanceof List) {
            return new JSONArray((List)value);
        } else {
            return value instanceof String ? (JSONArray)JSON.parse((String)value) : (JSONArray)toJSON(value);
        }
    }

  经过调试后发现,1.2.54版本在getJSONArray(String key)方法中使用的是(JSONArray)toJSON(value),而1.2.55版本在getJSONArray(String key)方法中使用的是return new JSONArray((List)value)。两者处理后返回的数据也确实不同。

fastjson 1.2.54 版本:

fastjson 1.2.54 版本

fastjson 1.2.55 版本:

fastjson 1.2.55 版本

  从调试情况看,1.2.54版本最终返回的是JSONObect,1.2.55版本返回的是LinkedTreeMap。Map结构toString()的结构肯定是“key=value”,而不是json结构。
  但是如果将测试代码中的GSON.fromJson替换成JSON.parseObject,那么不论fastjson的版本高低,都能正常运行。

  至此,我们知道了,fastjson在升级到1.2.55及以上版本后,getJSONArray方法对Google的Gson处理后的数据兼容性降低,或许本文的名字叫做《fastjson与Gson混用引发的bug》更合适。
  也不知道这算不算是bug,给官方提了个issue: > fastjson版本升级降低了对Gson的兼容性 #2814。

4、学习下fastjson对各种数据类型的处理

  在分析的过程中,看了fastjson中getJSONArray方法对各种数据类型的处理方式,和自己以前写的类似代码相比fastjson的代码更优雅,值得学习。相关方法com.alibaba.fastjson.JSON.toJSON(),有兴趣的同学可以看看。

// 此处代码仅展示核心结构,如需查阅完整代码请前往github/fastjson查看。
// toJSON简直是 数据类型分类处理的模板。@zxiaofan
@SuppressWarnings("unchecked")
    public static Object toJSON(Object javaObject, SerializeConfig config) {
        if (javaObject == null) {
            return null;
        }
        if (javaObject instanceof JSON) {
            return javaObject;
        }
        if (javaObject instanceof Map) {
            if (map instanceof LinkedHashMap) {
            } else if (map instanceof TreeMap) {
            } else {
                innerMap = new HashMap(size);
            }
            return json;
        }

        if (javaObject instanceof Collection) {
            for (Object item : collection) {
            }
            return array;
        }

        if (javaObject instanceof JSONSerializable) {
            return JSON.parse(json);
        }

        Class<!--?--> clazz = javaObject.getClass();

        if (clazz.isEnum()) {
            return ((Enum<!--?-->) javaObject).name();
        }

        if (clazz.isArray()) {
            for (int i = 0; i &lt; len; ++i) {
            }
            return array;
        }

        if (ParserConfig.isPrimitive2(clazz)) {
            return javaObject;
        }
        ObjectSerializer serializer = config.getObjectWriter(clazz);
        if (serializer instanceof JavaBeanSerializer) {
            return json;
        }
        String text = JSON.toJSONString(javaObject);
        return JSON.parse(text);
    }

5、总结

  • 正如文中总结,fastjson在升级到1.2.55及以上版本后,getJSONArray方法对Google的Gson处理后的数据兼容性降低,或许本文的名字叫做《fastjson与Gson混用引发的bug》更合适。
  • 代码规范:同一模块代码不允许混用Json解析工具;
  • 保持敬畏:生产发布,一定要保持敬畏,对变更充分回归;
  • 问题很简单,重要的是思考方式,在寻找答案的过程中学到更多。

> 敬畏生命,敬畏职责,敬畏规章。
当你认为没有错误的时候,错误一定会来找你。
--《中国机长》

本文相关分析代码:https://github.com/zxiaofan/OpenSource_Study/blob/master/fastjson/src/main/java/alibaba/fastjson/FastJsonBug.java


>祝君好运!
Life is all about choices!
将来的你一定会感激现在拼命的自己!
CSDN】【GitHub】【OSCHINA】【掘金】【微信公众号

© 著作权归作者所有

zxiaofan666

zxiaofan666

粉丝 3
博文 10
码字总数 22063
作品 0
成都
技术主管
私信 提问
加载中

评论(19)

w
wailouci
又升了一版到1.2.23(好像是这个版本)然后好像万事大吉。然后又有部分通过json反序列化成实体的类报告Date类型时间解析错误。在1.2.7版本里设置解析时间格式是yyyy-MM-dd HH🇲🇲ss一直没问题的。
w
wailouci
查询了出错的数据,就是因为mm有些没满足两位数,是9;最近我有发现一次bug,jsr310时间类toJsonStringDatetime解析bug,直接升到1.2.58。经过这几次确认这个框架的确有很多地方需要经过更多测试用例来审查版本的发布。深深感觉到我们就是小白鼠。
w
wailouci
fastjson1.2.12(注,官方代码维护者在其他网站是1.2.11能支持jsr310时间类,这个说法是错误的)以下不支持jsr310新的时间/日期API,一次版本升级遇到这个问题。在那次升级中还遇到springmvc通过asm生成的动态类,字段属性太长,这在1.2.7版本没有这个问题。
玄玉
玄玉
吓唬人,还以为真咋地了呢
zxiaofan666
zxiaofan666 博主
问题还是有点的,同样的代码版本升级就不行了。
King_Liu
King_Liu
//不知道为什么会有这行代码, 但是为了保持和原来的行为一致,还是保留下来
Object value = strangeCodeForJackson(object);
Joyzhou
Joyzhou
非spring项目估计会用fastjson,主要这东西现在不太关注,除了老项目会用工具类转换,否则基本用不上
zxiaofan666
zxiaofan666 博主
spring项目内部还是会有很多序列化操作噻,难道你们的项目没有?
Joyzhou
Joyzhou
有用都是基础用法,注入ObjectMapper就好了,对spring项目来说其实用什么都无所谓,所以就直接用默认的Jackson
张寒枫
张寒枫
Jackson才是王道,稳定,功能强大,速度快
zxiaofan666
zxiaofan666 博主
Gson也是很不错的选择
黑子鱼咖
黑子鱼咖
😛我项目中都是统一成jackson了
zxiaofan666
zxiaofan666 博主
Jackson一样有很多问题,国内不太关注吧了。我目前用fastjson和Gson较多。springboot让Jackson占了很大优势
黑子鱼咖
黑子鱼咖
这个是。我选jackson只是因为更习惯而已。fastjson中的某段注释依然在。我也就断了念头了
不要你觉得
不要你觉得
求问是啥注释内容呀
黑子鱼咖
黑子鱼咖
FastJsonHttpMessageConverter //不知道为什么会有这行代码, 但是为了保持和原来的行为一致,还是保留下来。@H_rj
zxiaofan666
zxiaofan666 博主
这个是替换项目默认序列化实现方式为fastjson吧,只在接口以及调用层级生效。
黑子鱼咖
黑子鱼咖
回复 @zxiaofan666 : 😳我是debug的时候发现的。然后就列入黑名单了。各有所好
H_rj
H_rj
同问
Fastjson 爆出远程代码执行高危漏洞,更新版本已修复

fastjson近日曝出代码执行漏洞,恶意用户可利用此漏洞进行远程代码执行,入侵服务器,漏洞评级为“高危”。 基本介绍 fastjson 是一个性能很好的 Java 语言实现的 JSON 解析器和生成器,来自...

南湖船老大
2017/03/16
22.3K
28
fastjson 1.2.60 发布,修复导致 DoS 的问题

fastjson 1.2.60 发布了,这是一个 bug 修复安全加固版本,增加了 AutoType 黑名单,修复了一个导致拒绝服务的问题。 具体更新内容: 安全增强,增加 AutoType 黑名单,修复特定场景导致拒绝...

h4cd
09/09
7.7K
12
Fastjson 安全更新,建议升级到 1.2.28 或更新版本

安全升级公告 最近发现 fastjson 在 1.2.24 以及之前版本存在高危安全漏洞,为了保证系统安全,请升级到 1.2.28 或者更新版本。 更新方法 1. Maven 依赖配置更新 通过 maven 配置更新,使用最...

局长
2017/03/15
12.1K
9
遭遇Tomcat远程拒绝服务漏洞

接到腾讯安全部门的邮件,大意是 Tomcat远程拒绝服务漏洞的攻击代码(漏洞CVE编号CVE-2010-2227,http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2227 ),攻击者可以使用此漏洞令T...

余二五
2017/11/22
0
0
【源资讯 第01期】美国互联网瘫痪,码云、龙芯CPU、斯托曼、“脏牛”漏洞也来凑热闹

本周最受关注的无疑就是轰动一时的【DynDNS 遭到 DDoS 攻击,半个美国互联网瘫痪】原本以为只有在电影上才能看到的场面,居然在现实中发生了,那么事件到底是怎么样的呢: 美国东部时间周五(...

两味真火
2016/10/28
792
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周五乱弹 —— 你已经是个成熟的熊猫了

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @Sharon啊 :#今日歌曲推荐# 分享黑鸭子的单曲《羞答答的玫瑰静悄悄的开》 《羞答答的玫瑰静悄悄的开》- 黑鸭子 手机党少年们想听歌,请使劲儿...

小小编辑
7分钟前
16
4
结合Spring Security进行web应用会话安全管理

在本文中,将为大家说明如何结合Spring Security 和Spring Session管理web应用的会话。 一、Spring Security创建使用session的方法 Spring Security提供4种方式精确的控制会话的创建: alwa...

fightinging
12分钟前
2
0
83、Mybatis和Hibernate重要区别

Mybatis;入门简单,程序容易上手开发,节省开发成本。Mybatis需要程序猿自己编写sql语句,是一个不完全的ORM框架,对sql修改和优化非常容易实现。 Mybatis适合开发需求变更频繁的系统,比如...

lianbang_W
今天
5
0
设计模式之状态模式

定义 Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.(当一个对象内在状态改变时允许其改变行为,这个对象看起来像改...

陈年之后是青葱
今天
6
0
Python常用模块之os.path

os.path.abspath(path) 输入相对路径,返回绝对路径 Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32Type "copyright", "credits" or "lic......

松鼠大帝
今天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部