• fastjson从1.1.41升级到1.2.28的坑


    最近因为fastjson安全漏洞,升级jar包时,踩了一些坑。

    新版本FastJsonHttpMessageConverter初始化,默认设置MediaType为*/*

    背景:
    使用Spring RestTemplate,配置如下:

        <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
            <constructor-arg ref="ky.clientHttpRequestFactory"/>
            <property name="errorHandler">
                <bean class="org.springframework.web.client.DefaultResponseErrorHandler"/>
            </property>
            <property name="messageConverters">
                <list>
                    <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
                    <bean class="cn.com.autodx.common.jsonView.ViewAwareJsonMessageConverter">
                    </bean>
                    <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                        <property name="supportedMediaTypes">
                            <list>
                                <value>text/html;charset=UTF-8</value>
                                <value>application/json</value>
                                <value>text/javascript;charset=utf-8</value>
                            </list>
                        </property>
                    </bean>
                </list>
            </property>
        </bean>
    

    其中ViewAwareJsonMessageConverter继承自FastJsonHttpMessageConverter。
    fastjson从1.1.41升级到1.2.28之后,请求报错:

    java.lang.IllegalArgumentException: 'Content-Type' cannot contain wildcard type '*'
    

    原因是在1.1.41中,FastJsonHttpMessageConverter初始化时,设置了MediaType。

        public FastJsonHttpMessageConverter(){
            super(new MediaType("application", "json", UTF8), new MediaType("application", "*+json", UTF8));
        }
    

    而在1.2.28中,设置的MediaType为‘/’,即:

        public FastJsonHttpMessageConverter() {
            super(MediaType.ALL);  // */*
        }
    

    后续在org.springframework.http.converter.AbstractHttpMessageConverter.write过程中,又要判断Content-Type不能含有通配符,这应该是一种保护机制,并强制用户自己配置MediaType。代码如下:

    	@Override
    	public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage)
    			throws IOException, HttpMessageNotWritableException {
    		final HttpHeaders headers = outputMessage.getHeaders();
    		if (headers.getContentType() == null) {
    			MediaType contentTypeToUse = contentType;
    			if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
    				contentTypeToUse = getDefaultContentType(t);
    			}
    			if (contentTypeToUse != null) {
    			//设置Content-Type,不允许含有通配符
    				headers.setContentType(contentTypeToUse);
    			}
    		}
    		......
    
    		if (outputMessage instanceof StreamingHttpOutputMessage) {
    			......
    		}else {
    		//自定义MessageConverter的write操作
    			writeInternal(t, outputMessage);
    			outputMessage.getBody().flush();
    		}
    	}
    
    	public void setContentType(MediaType mediaType) {
    		Assert.isTrue(!mediaType.isWildcardType(), "'Content-Type' cannot contain wildcard type '*'");
    		Assert.isTrue(!mediaType.isWildcardSubtype(), "'Content-Type' cannot contain wildcard subtype '*'");
    		set(CONTENT_TYPE, mediaType.toString());
    	}
    

    所以,需要为ViewAwareJsonMessageConverter设置supportedMediaTypes:

    <bean class="cn.com.autodx.common.jsonView.ViewAwareJsonMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>application/json;charset=UTF-8</value>
                <value>application/*+json;charset=UTF-8</value>
            </list>
        </property>
    </bean>
    

    新版本序列化默认不再对字段进行排序

    这个是一个签名算法的场景:客户端对参数进行序列化,然后md5加密成一个签名;服务端按照相同的算法解析一遍参数,对比签名值。这里加密依赖json序列化之后的字符串,也就依赖序列化时字段的排序。

    这是fastjson做了一个性能优化,将排序需求抽象出一个SerializerFeature,供用户自己配置。如果需要排序场景,在序列化时添加参数SerializerFeature.MapSortField即可,即:
    JSON.toJSONString(obj, SerializerFeature.MapSortField);

    官方文档

    1.2.3之后的版本,Map的序列化没有做排序再输出,原因是通过TreeMap排序很影响性能。1.2.27版本中增加SerializerFeature.MapSortField实现同样的功能。 使用方法如下: a) 传入SerializerFeature.MapSortField参数。 JSON.toJSONString(map, SerializerFeature.MapSortField); b) 通过代码修改全局缺省配置。 JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.MapSortField.getMask(); c) 通过JVM启动参数配置修改全局配置 -Dfastjson.serializerFeatures.MapSortField=true d) 通过类路径下的fastjson.properties来配置 fastjson.serializerFeatures.MapSortField=true

    新老版本序列化和反序列化不兼容,会出乱码。

    具体没有查证从哪一个版本开始不兼容,所以如果涉及到上下游之间的交互,需要同时升级。囧

  • 相关阅读:
    亲手使用Sencha Touch + phonepag开发Web APP随笔 -- 第一个APP
    亲手使用Sencha Touch + phonepag开发Web APP随笔 -- 环境安装篇
    安装Ruby下的compress失败
    Centos 6.5安装bugzilla 5.0.2
    Win7+Eclipse+Hadoop2.6.4开发环境搭建
    [整理]Centos6.5 + hadoop2.6.4环境搭建
    js 使用技巧
    css 样式小窍门
    fpm rpm制作
    nginx rewrite
  • 原文地址:https://www.cnblogs.com/shoren/p/fastjson.html
Copyright © 2020-2023  润新知