核心是反序列化前拒绝非法类,而非中途拦截;必须用jdk内置serialfilter做jvm级白名单(如-djdk.serialfilter="java.base/;com.mycompany.dto.;!"),配合微服务统一安全入口封装,禁用原生序列化传输。

Java 微服务中反序列化未知数据时,防止恶意类加载和 RCE 的核心不是“在反序列化中途拦截”,而是在反序列化开始前就拒绝非法类。ObjectInputStream 本身不提供“拦截未知类后继续”的钩子——它要么加载并执行(危险),要么抛异常中断(安全但需提前阻断)。真正可行且生产推荐的方式,是利用 JDK 内置的序列化过滤器机制(serialFilter),配合微服务上下文做白名单管控。
✅ 用 jdk.serialFilter 做 JVM 级白名单控制
这是最轻量、兼容性最好、无需改业务代码的防御手段,尤其适合 Spring Boot 微服务中处理 Redis 缓存反序列化、RMI 调用、MQ 消息体等场景。
-
启动参数配置(推荐):
-Djdk.serialFilter="java.base/*;java.desktop/*;com.mycompany.dto.**;!*"
-
java.base/*:放行基础 JDK 类(如 String、List、Integer) -
com.mycompany.dto.**:只允许你自己的 DTO 包及其子包(如com.mycompany.dto.user.UserDTO) -
!*:兜底拦截一切未显式声明的类(顺序关键,必须放最后)
-
-
动态设置(测试或运行时调整):
System.setProperty("jdk.serialFilter", "com.mycompany.model.**;java.lang.*;!*");
⚠️ 注意:该过滤器在 ObjectInputStream.readObject() 第一步 resolveClass() 时触发,早于任何 gadget 方法执行,因此能真正阻断攻击链。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
✅ 在微服务框架层封装安全的反序列化入口
不要直接暴露 ObjectInputStream 给业务。统一收口,例如:
public class SafeObjectDeserializer {
private static final ObjectInputStream.Filter SERIALIZATION_FILTER =
ObjectInputStream.createFilter("com.mycompany.model.**;java.lang.*;!*");
public static <t> T deserialize(byte[] bytes, Class<t> expectedType) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais) {
@Override
protected Class> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
// 强制使用预设 filter(JDK 9+ 默认生效,但显式调用更可靠)
if (SERIALIZATION_FILTER != null) {
FilterResult result = SERIALIZATION_FILTER.checkInput(
desc.getName(), desc.getSerialVersionUID(),
-1, -1, -1
);
if (result == FilterResult.REJECTED) {
throw new InvalidClassException("Class rejected by filter: " + desc.getName());
}
}
return super.resolveClass(desc);
}
}) {
return expectedType.cast(ois.readObject());
}
}
}</t></t>
这样既复用 JDK 过滤能力,又避免开发者误用裸 ObjectInputStream。
❌ 不要依赖自定义 ObjectInputStream 子类做校验
有人重写 checkResolveClass() 或 resolveClass() 手动比对类名白名单,但存在严重缺陷:
- 它只控制类加载,不阻止已加载类内部的危险逻辑(如
BadAttributeValueExpException.readObject()调用Runtime.exec()) - 若反序列化路径被绕过(如通过
sun.misc.Unsafe或第三方库如 JBoss Marshalling),过滤完全失效 - 微服务中常混用 Jackson / Kryo / Protobuf,这类手动过滤对非 Java 原生序列化无效
✅ 微服务场景下的额外加固建议
-
禁用 Java 原生序列化传输:RPC 优先用 JSON(Jackson)、Protobuf 或 gRPC;缓存用 String/JSON 存储,而非
byte[]直存对象 -
Redis 反序列化特别注意:若用
GenericJackson2JsonRedisSerializer,确保 DTO 类无敏感 getter/setter(避免 Jackson 反序列化 gadget) -
日志与告警:捕获
InvalidClassException和ClassNotFoundException,记录被拦截的类名,用于发现潜在探测行为
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










