必须替换默认messageconverter,因simplemessageconverter对pojo默认启用jdk序列化,存在反序列化任意类安全风险(如cve-2023-34050)、不可跨语言、易因类变更失败,应改用jackson2jsonmessageconverter并配content-type为application/json。

在 Spring Boot 中使用 RabbitMQ 时,若不显式配置 MessageConverter,Spring AMQP 默认会使用 SimpleMessageConverter,而它对非字符串/字节数组类型的消息(如自定义对象)会退回到 JDK 序列化(Serializable),这不仅不安全、不可跨语言,还容易因类结构变更导致反序列化失败。
为什么必须替换默认 MessageConverter
默认的 SimpleMessageConverter 在处理 Object 类型消息时,会调用 SerializationUtils.serialize(),底层依赖 ObjectOutputStream。只要发送方没指定 content-type、也没手动转成 JSON 字节数组,就可能触发 JDK 序列化——哪怕你用了 @RabbitListener 接收 POJO,底层仍可能悄悄序列化。
关键点:JDK 序列化不是“可选行为”,而是 SimpleMessageConverter 的 fallback 逻辑,只要类型不是 String、byte[]、byte[][] 或基础类型包装类,就会走这条路。
用 Jackson2JsonMessageConverter 彻底禁用 JDK 序列化
推荐使用 Jackson2JsonMessageConverter,它默认只处理 JSON 格式,不支持任何 JDK 序列化路径。启用后,一旦消息体无法解析为 JSON,会直接抛异常,而不是降级到 ObjectInputStream。
- 在配置类中声明 Bean,覆盖默认 converter:
@Configuration
public class RabbitMQConfig {
@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
}- 确保发送端明确设置 content-type(可选但强烈建议):
MessageProperties props = new MessageProperties();
props.setContentType("application/json");
props.setContentEncoding("UTF-8");
Message message = new Message(jsonBytes, props);
rabbitTemplate.send("exchange", "routing.key", message);- 或更简洁地,直接用
convertAndSend(自动应用 converter):
rabbitTemplate.convertAndSend("exchange", "routing.key", myOrderDto); // 自动转 JSON进阶:彻底堵死 JDK 序列化入口(防御性配置)
即使替换了 converter,某些旧代码若手动构造 Message 并传入 Serializable 对象,仍可能绕过 converter。为根除风险,可禁用 Spring AMQP 的序列化支持:
- 在
application.yml中关闭自动序列化检测:
spring:
rabbitmq:
listener:
simple:
# 禁用对 Serializable 类型的隐式支持
acknowledge-mode: manual
# 关键:显式禁用 fallback 到 JDK 序列化
template:
mandatory: true- 自定义
SimpleMessageConverter的子类,重写createMessage()和fromMessage(),遇到非 JSON 类型直接 throw:
public class StrictJsonMessageConverter extends Jackson2JsonMessageConverter {
@Override
protected Message createMessage(Object object, MessageProperties messageProperties) {
if (!(object instanceof String) && !(object instanceof byte[])) {
// 强制要求只能是 String 或 byte[],拒绝 POJO 直接传入
throw new IllegalArgumentException("Only String or byte[] allowed. Use convertAndSend for POJOs.");
}
return super.createMessage(object, messageProperties);
}
}验证是否生效的实操检查点
部署前快速确认 JDK 序列化已被切断:
- 启动应用后,查看日志是否包含
Creating bean with name 'jsonMessageConverter',且无SimpleMessageConverter初始化记录; - 发一条 Map 类型消息:
rabbitTemplate.convertAndSend("q", Collections.singletonMap("k", "v")),抓包看 payload 是否为{"k":"v"}而非乱码二进制; - 故意发送一个未实现
Serializable的类实例,应抛HttpMessageNotWritableException或JsonProcessingException,而非InvalidClassException。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











