一、漏洞概述
5 月 23 日, 官方发布公告称在 1.2.80 及以下版本中存在新的反序列化风险,在特定条件下可绕过默认 autoType 关闭限制,从而反序列化有安全风险的类,攻击者利用该漏洞可实现在目标机器上的远程代码执行。
spring cloud alibaba sentinel 中依赖 fastjson 传递依赖引入,请相关用户尽快采取防护措施。
影响范围
受影响版本
Fastjson ≤ 1.2.80
不受影响版本
Fastjson = 1.2.83
二、罪魁祸首 AutoType
fastjson、jackson 都支持 AutoType 功能,这个功能在序列化的 JSON 字符串中带上类型信息,在反序列化时,不需要传入类型,实现自动类型识别。
三、fastjson1 安全问题
fastjson 1.x 内部维护了一个白名单,java 发展近 30 年难免有些漏网之鱼,这也造成近几年 fastjson 安全漏洞频发,养活了一大票安全人员。
四、jackson AutoType 处理
同样,jackson 也支持 AutoType,jackson 爆出的几次安全漏洞也跟它有关。Jackson 的 json 解析跟 ObjectMapper 绑定,我们可以根据不同的需求来定制 ObjectMapper。
例如:只在 redis 序列化和反序列时激活 DefaultTyping。(示例代码,mica-redis 中采用 ObjectMapper copy 生成新的 ObjectMapper bean 避免污染全局 ObjectMapper 造成不安全)
public RedisSerializer<Object> redisSerializer(ObjectProvider<ObjectMapper> objectProvider) {
// jackson findAndRegisterModules,use copy
ObjectMapper objectMapper = objectProvider.getIfAvailable(ObjectMapper::new).copy();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// findAndRegisterModules
objectMapper.findAndRegisterModules();
// class type info to json
GenericJackson2JsonRedisSerializer.registerNullValueSerializer(objectMapper, null);
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), DefaultTyping.NON_FINAL, As.PROPERTY);
return new GenericJackson2JsonRedisSerializer(objectMapper);
}
五、fastjson2 的设计
-
fastjson2 AutoType 必须显示打开才能使用,没有任何白名单,也不包括任何 Exception 类的白名单。这可以保证缺省配置下是安全的。
序列化带上类型信息
序列化是带上类型信息,需要使用 JSONWriter.Feature.WriteClassName。比如:
Bean bean = ...;
String jsonString = JSON.toJSONString(bean, JSONWriter.Feature.WriteClassName);
很多时候,root对象是可以知道类型的,里面的对象字段是基类或者不确定类型,这个时候不输出root对象的类型信息,可以减少序列化结果的大小,也能提升反序列化的性能。
Bean bean = ...;
String jsonString = JSON.toJSONString(bean, JSONWriter.Feature.WriteClassName, JSONWriter.Feature.NotWriteRootClassName);
反序列化打开AutoType功能支持自动类型
Bean bean = (Bean) JSON.parseObject(jsonString, Object.class, JSONReader.Feature.SupportAutoType);
-
fastjson2 AutoType 支持配置 safeMode,在 safeMode 打开后,显式传入 AutoType 参数也不起作用,具体配置如下:
-Dfastjson2.parser.safeMode=true
-
fastjson2 AutoType 会经过内置黑名单过滤。该黑名单能拦截大部分常见风险,这个机制不能保证绝对安全,打开 AutoType 不应该在暴露在公网的场景下使用。这点无可厚非,毕竟 AutoType 的场景不是在 web api,
六、升级到 fastjson2
6.1 兼容模式升级
升级可以通过兼容模式升级,兼容模式不需要改代码,但在深度使用的场景,如果原来使用fastjson 1.2.x
版本,可以使用兼容包,兼容包不能保证100%兼容,请仔细测试验证,发现问题请及时反馈。 https://github.com/alibaba/fastjson2/issues
Fastjson v1
兼容模块,Maven依赖,如当前版本<version>2.0.4</version>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson2.version}</version>
</dependency>
6.2 使用新API升级
使用新API是建议的升级方式,使用新的API能获得更多的功能。
-
包名编程
FASTJSON
v2和1.x版本使用不同的package,新的package名称是com.alibaba.fastjson2,新package和之前不同,可以实现1.x和2.x共存
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONArray;
-
Maven依赖 Maven依赖的groupId和1.x不同,使用了新的groupId
com.alibaba.fastjson2
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson2.version}</version>
</dependency>
如果你需要用到spring支持的功能,还需要依赖fastjson2-extension
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension</artifactId>
<version>${fastjson2.version}</version>
</dependency>
笔者尝试升级的一个项目依赖比较少,并且也没有强制依赖 fastjson1,另外项目中也没用到一些奇淫技巧。所以选择了比较激进的直接升级新 API。
另外有使用 FastJsonHttpMessageConverter
也是更改一下包名即可。
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
更改为:
import com.alibaba.fastjson2.support.config.FastJsonConfig;
import com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter;
proxyBeanMethods = false)
(public class FastJsonConfiguration {
public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
converter.setFastJsonConfig(new FastJsonConfig());
converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType("application", "*+json")));
return converter;
}
}
最后
fastjson2 在性能和安全上都得到了很好的提升,特别是支持了 jsonb,在缓存、rpc 等场景优先考虑 jsonb
文章评论