fastjson class泄漏
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了fastjson class泄漏相关的知识,希望对你有一定的参考价值。
问题描述
fastjson在jetty容器中序列化HttpServletRequest会导致class泄漏,严重时会导致meta区溢出,导致无限FGC。
fastjson序列化流程
fastjson通过动态生成代码提高序列化速度,序列化逻辑如下:
String serialize(Object object) { // 先看是否已经存在对应的serializer Serializer serializer = serializerCache.get(object.getClass()); if (serializer == null) { // 通过动态生成代码的方式,创建新的序列器类 Class<?> serializerClass = createSerializerClass(object.getClass()); serializer = serializerClass.newInstance(); serializerCache.put(object.getClass(), serializer); } return serializer.serialize(object); }
如果传入的object类型是org.eclipse.jetty.server.Request,serializerClass.newInstance会出现异常。因此每次序列化org.eclipse.jetty.server.Request,都会生成一个serializerClass。即出现了class泄漏。
PS: org.eclipse.jetty.server.Request是jetty中HttpServletRequest的实现类,下面简称Request
newInstance()为什么会失败?
fastjson生成的serializerClass结构如下:
import org.eclipse.jetty.server.Request; class Serializer_XXX { // Request中每个字段对应一个xxx_asm_field_type字段 Type context_asm_field_type; Type userIdentityScope_asm_field_type; // 其他字段省略 ... // 构造函数 Serializer_XXX() { context_asm_field_type = getFieldType( Request.class, "context"); userIdentityScope_asm_field_type = getFieldType( Request.class, "userIdentityScope"); // 其他字段忽略 ... } }
构造函数会执行失败,原因是找不到org.eclipse.jetty.server.Request。
为什么找不到类?
问题涉及到的3个classloader,它们的结构如下:
ServerClassLoader -> WebAppClassLoader -> AsmClassLoader
Request的classloader是ServerClassLoader,Serializer_XXX的classloader是AsmClassLoader。
按照类加载的约定,加载Request类的流程如下:
理论上Request是可以成功加载的。问题出在WebAppClassLoader,它违反了类加载的约定,没有让parent加载,而是自己直接加载,结果找不到,就直接抛ClassNotFoundException。
WebAppClassLoader的行为是可配置的,如果启动参数org.eclipse.jetty.server.webapp.parentLoaderPriority是true,它就会先让parent找,否则就自己找,默认是false
fastjson的问题在哪里?
fastjson实际是有考虑类加载的问题的,它是判断Request的ClassLoader是不是AsmClassLoader或AsmClassLoader的祖先。
但是由于WebAppClassLoader违背了类加载的约定,fastjson的判断就变得不可靠了。
以上是关于fastjson class泄漏的主要内容,如果未能解决你的问题,请参考以下文章
高危!Fastjson反序列化远程代码执行漏洞风险通告,请尽快升级
高危,Fastjson反序列化远程代码执行漏洞风险通告,请尽快升级