fastjson2 打开 AutoType

发布时间 2023-09-01 15:20:49作者: 修烛

1. 功能简介

FASTJSON支持AutoType功能,这个功能在序列化的JSON字符串中带上类型信息,在反序列化时,不需要传入类型,实现自动类型识别。

2. AutoType安全机制介绍

  • 必须显式打开才能使用。和fastjson 1.x不一样,fastjson 1.x为了兼容有一个白名单,在fastjson 2中,没有任何白名单,也不包括任何Exception类的白名单,必须显式打开才能使用。这可以保证缺省配置下是安全的。
  • 支持配置safeMode,在safeMode打开后,显式传入AutoType参数也不起作用
  • 显式打开不推荐,打开后会有反序列化风险,打开AutoType不应该在暴露在公网的场景下使用。建议参照本文中的第5点代替AutoType功能。

3. fastjson2如何正确的打开autoType的功能

正常情况下,出于安全考虑,我们默认是关闭autoType的能力的,但是可以通过构建AutoTypeBeforeHandler白名单的方式来打开,废话不多说,上代码

package com.example.es.fastjson2;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.Filter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author peng.hu1
 * @Date 2023/9/1 14:45
 */
@Slf4j
public class JSonSerializer {

    public JSONWriter.Feature[] features = new JSONWriter.Feature[]{
            JSONWriter.Feature.WriteClassName,
            JSONWriter.Feature.FieldBased,
            JSONWriter.Feature.ReferenceDetection,
            JSONWriter.Feature.NotWriteDefaultValue,
            JSONWriter.Feature.WriteNameAsSymbol,
            JSONWriter.Feature.WriteEnumsUsingName
    };

    private static final Filter autoTypeFilter;


    static {
        autoTypeFilter = JSONReader.autoTypeFilter(
                // 按需加上需要支持自动类型的类名前缀,范围越小越安全, 我这个就比较过分了,直接全部放开,哈哈
                "com.",
                "org.",
                "java."
        );
    }

    /**
     * 序列化
     * @param object 对象
     * @param classLoader
     * @return
     */
    public byte[] serialize(Object object, ClassLoader classLoader) {
        ClassLoader swap = Thread.currentThread().getContextClassLoader();
        try {
            if (classLoader != null) {
                Thread.currentThread().setContextClassLoader(classLoader);
            }
            return JSON.toJSONBytes(object, features);
        } catch (Throwable t) {
            log.error("SerializeException" ,t);
            throw new RuntimeException("serialize error", t);
        } finally {
            if (classLoader != null) {
                Thread.currentThread().setContextClassLoader(swap);
            }
        }
    }

    public <T> T deserialize(byte[] bytes, Class<T> type, ClassLoader classLoader) {
        ClassLoader swap = Thread.currentThread().getContextClassLoader();
        try {
            if (classLoader != null) {
                Thread.currentThread().setContextClassLoader(classLoader);
            }
            try {
                return JSON.parseObject(bytes, type, autoTypeFilter,
                        JSONReader.Feature.UseDefaultConstructorAsPossible,
                        JSONReader.Feature.UseNativeObject,
                        JSONReader.Feature.FieldBased
                );
            } catch (Exception e) {
                return JSON.parseObject(bytes, type);
            }

        } catch (Throwable t) {
            log.error("SerializeException" ,t);
            throw new RuntimeException("deserialize error", t);
        } finally {
            if (classLoader != null) {
                Thread.currentThread().setContextClassLoader(swap);
            }
        }
    }
}

这里面最核心的地方就在这里 JSONReader.autoTypeFilter("*"), 这个是个白名单过滤filter