继去年1.2.47 Fastjson被绕过之后,最近的1.2.68又出现了绕过。
正好前段时间翻了一遍Fastjson的源码,对整体逻辑有了一些了解,就尝试分析下autotype的校验过程,以及这两次绕过的思路。若有错误,还望指出。
autotype的校验
为什么校验一直被绕过
1.2.24之后,fastjson对反序列化的类型进行了校验,主要就体现在ParserConfig.checkAutoType函数中
里面会对反序列化的类型进行黑白名单和校验,然后获取对应的Java类。
至于为什么没开启SupportAutoType属性依然会存在反序列化的危险呢?
可以看到在解析过程中,只要key值为@type时,就会进入checkAutoType函数尝试获取类。
而且校验SupportAutoType属性的工作却是在checkAutoType函数中完成的(跟进之后也可以看到是在函数最末端调校验的值,并且在这之前有多处return)
那为什么要有这种设计呢?主要原因在于fastjson想让一些基础类(还有一些白名单中的异常类)可以不受SupportAutoType限制就可以反序列化。
例如之前别人提出的验证是否使用fastjson的java.net.Inet6Address、java.net.URL也都是这个原理。
可以看到,即使不开启SupportAutoType依然是可以获取到具体的java类的。
所以,这就是为什么校验一直被绕过,感觉主要原因就在于为了实现这个feature,而导致的一些逻辑问题。
校验过程
checkAutoType主要有三个参数
String typeName 被序列化的类名
Class> expectClass 期望类
int features 配置的feature值
先简单说下expectClass这个期望类,它的主要目的是为了让一些实现了expectClass这个接口的类可以被反序列化。
然后来看下校验的过程,一开始就是一些非null和长度限制的判断
之后判断exceptClass的类型,如果非null并且不是如下类型,则设置expectClassFlag为true
简单说的话就是不允许如下类型的exceptClass
Object.class
Serializable.class
Cloneable.class
Closeable.class
EventListener.class
Iterable.class
Collection.class
之后比较长的一个部分就是比较类的哈希值,是否在内部白名单和内部黑名单中
如果在不在内部白名单并且 开启了SupportAutoType 或者 存在期望类时:如果在白名单中则直接加载,在黑名单中则异常退出。(讲起来有点绕,直接看代码可能好点)
String className = typeName.replace('$', '.');
Class> clazz;
final long BASIC = 0xcbf29ce484222325L;
final long PRIME = 0x100000001b3L;