ThinkPHP改用Redis存储Session可显著降低反序列化风险,关键在于停用File驱动、统一使用PHP原生序列化、严格隔离Redis库与key前缀、避免用户原始输入直写Session。

ThinkPHP 的 Session 改用 Redis 本身不能直接“防止反序列化利用”,但能显著降低相关风险——关键在于避开文件型缓存驱动中可被注入执行的 PHP 文件写入路径,同时通过正确配置规避因序列化方式不一致导致的反序列化失败或误解析。真正的防护重点是:禁用危险驱动、统一序列化协议、隔离存储空间、避免用户数据直写 Session。
停用 File 驱动,彻底切断 PHP 文件写入链
ThinkPHP 默认使用文件存储 Session(type => 'file'),而漏洞常出现在 think\cache\driver\File::set() 中:它把用户可控内容拼进 <?php // ... > 再写成 .php 文件。攻击者用换行符(%0a)绕过注释封装,让后续代码被执行。
- 在
config/session.php中必须设'driver' => 'redis',且确认没有其他地方调用ini_set('session.save_handler', 'files') - 检查入口文件(如
public/index.php)或中间件,删掉任何手动启用原生 PHP session 的代码,例如:session_start()或ini_set('session.save_handler', ...) - 确保 PHP 配置中
session.auto_start = Off、session.use_trans_sid = Off(TP 不会自动关,必须手动关)
强制使用 PHP 原生序列化,避免格式错乱
Redis 驱动下,Session 数据会被序列化后存入 key。若前后端或不同版本 TP 使用不同序列化方式(如 json vs serialize),会导致 unserialize() 失败,$_SESSION 为空——这虽不直接触发 RCE,但可能掩盖真实问题,或在 fallback 场景中意外激活危险逻辑(如 TagCache 反序列化)。
审查 Remix v2 代码中的 v1 形态 meta 导出(v2 中为破坏性变更),cookie 安全漏洞(httpOnly、secure、密钥轮换),认证门位于错误层级,以及其他
- 在
config/session.php的 redis 配置块中添加:'serialize' => 'php' - 该选项仅在 ThinkPHP 6.0.10+ 有效;低版本需重写
think\session\driver\Redis的read()和write()方法,在读取后加unserialize()、写入前加serialize() - 不要混用 TP5 和 TP6 的 Session 数据,二者默认序列化方式不同(5.x 用
serialize,6.x 早期用json_encode)
严格区分 key 前缀与数据库,防误删和碰撞
共用 Redis DB 或相同 prefix 会导致缓存 key 和 session key 混杂。一旦执行 FLUSHDB 或误删 KEYS tp6:*,所有登录态瞬间丢失;更严重的是,多个应用若 key 名相同(如都叫 think:session:abc123),会相互覆盖 session,为会话劫持埋下隐患。
立即学习“PHP免费学习笔记(深入)”;
- 在
config/session.php中为 Redis 配置专属前缀:'redis' => ['prefix' => 'sess:tp6_admin_'] - 在
config/cache.php中为缓存设置不同前缀:'stores.redis.prefix' => 'cache:tp6_admin_' - 显式指定 database(如
'database' => 2),不依赖默认 0 库,与缓存、队列物理隔离
不往 Session 存用户原始输入,从源头减少风险
即使用了 Redis,如果业务代码把未过滤的 $_POST、$_GET 直接塞进 session()->set(),仍可能在后续反序列化、日志记录、调试输出等环节引发问题(比如含不可见字符、嵌套对象、资源句柄等)。
- 只存必要字段:用户 ID、角色、登录时间、IP 等结构化数据,避免存整个请求体或 raw input
- 对存入数据做白名单过滤或类型校验,例如:
session()->set('user_id', (int)$id) - 敏感操作(如支付、密码修改)不依赖 Session 中的宽松标识,应二次验证 token 或签名


















