redis中会话数据通常为序列化字节流,常见格式包括java原生序列化(byte[])、json字符串或protobuf等;反序列化需确保类可加载、serialversionuid匹配,并通过白名单、签名校验等机制防范漏洞,同时避免transient资源与类型混淆。

Java 中从分布式缓存(如 Redis)反序列化恢复会话状态,本质是“读取字节流 → 构造对象 → 绑定到当前请求上下文”的过程。关键不在于缓存本身,而在于如何安全、准确地把缓存里的二进制数据还原成可用的 HttpSession 或自定义会话对象。
缓存中存的是什么格式?
分布式缓存里存储的会话数据,通常不是明文字符串,而是序列化后的字节流。常见形式有:
- 使用 Java 原生序列化:直接调用
ObjectOutputStream写入,缓存中存的是byte[],含类名、字段描述、值等完整元数据; - 使用 JSON(如 Jackson):会话对象被转为 JSON 字符串再存入 Redis,反序列化时走 JSON 解析,不依赖
Serializable; - 使用 Protobuf/Hessian 等轻量协议:需配套 schema 或注册类,体积小、性能高,但需统一客户端/服务端协议。
若用原生序列化,必须确保缓存中的类在反序列化时能被当前 ClassLoader 加载,且 serialVersionUID 匹配,否则抛 InvalidClassException。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
反序列化前要校验来源与类型
从 Redis 读出的字节流属于外部输入,不可信。盲目调用 ObjectInputStream.readObject() 会触发反序列化漏洞(如利用 Commons Collections gadget 执行命令)。必须做两层控制:
- 禁用默认反序列化逻辑:不要直接 new
ObjectInputStream,而是继承它并重写resolveClass(); - 白名单机制:只允许加载明确声明的会话相关类,例如
MyUserSession、CartData,拒绝Runtime、URL、TemplatesImpl等危险类; - 附加签名或 MAC 校验:在序列化时对字节流加签,反序列化前先验签,防止缓存被篡改。
会话对象需支持跨节点一致性
反序列化出来的对象,要能无缝接入当前 Web 容器(如 Tomcat)的会话管理流程。实际做法分两类:
-
容器级集成:用 Spring Session 或 Tomcat Redis Session Manager。它们封装了反序列化逻辑,自动将 Redis 中的 session ID 映射为
HttpSession实例,并在readObject前注入安全过滤器; -
应用级手动管理:从 Redis 拿到
byte[]后,用自定义ObjectInputStream安全还原对象,再通过request.setAttribute("session", obj)或放入 ThreadLocal,供业务代码使用。此时对象不应含transient的连接资源(如 DB Connection),否则反序列化后失效。
避免常见陷阱
很多团队踩过这些坑:
- 缓存中存了未实现
Serializable的类(比如用了 Lombok 的@Data但忘了加接口),反序列化直接报NotSerializableException; - 升级服务时修改了会话类字段(删了
address,加了regionId),没更新serialVersionUID,老缓存数据无法加载; - Redis 中混存了用户会话和定时任务快照,反序列化时类型判断缺失,把
ScheduledTask当UserSession解析,导致运行时异常; - 用
StringRedisTemplate存了 JSON,却用JdkSerializationRedisSerializer去读,字节不匹配,抛StreamCorruptedException。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










