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

新老版本序列化和反序列化不兼容,會出亂碼。

具體沒有查證從哪一個版本開始不兼容,所以如果涉及到上下游之間的交互,需要同時升級。囧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM