最有效防护是直接禁用不可信输入的unserialize()调用;需全项目清理危险调用点、强制启用allowed_classes白名单、禁用Phar协议、改用JSON/MessagePack替代。

直接禁用不可信输入的 unserialize() 调用,是最有效、最根本的防护动作。PHP 本身不会自动识别恶意序列化字符串,风险完全来自开发者把用户可控数据(如 $_GET、$_POST、Cookie、缓存内容)未经校验就喂给 unserialize()。
彻底清理危险调用点
全项目搜索 unserialize(、->unserialize(、Str::unserialize 等关键词,重点排查:
- 控制器里类似
unserialize($_GET['data'])的调试或兼容代码——必须删除,改用json_decode($input, true) - Redis/Memcached 缓存读取逻辑——确认是否直接反序列化;若使用 Redis,需在
config/cache.php中设'serialize' => false,统一用 JSON 存取 - Session 驱动(如 Memcache)中可能被污染的 session 数据还原逻辑——建议转为 JSON + JWT 签名存储,由网关统一验证
- 日志回放、错误上下文还原、测试路由等临时功能中的残留入口——全部下线或加访问控制
强制启用 allowed_classes 白名单
PHP 7.4+ 支持白名单参数,这是轻量但强效的兜底机制:
- 将所有
unserialize($data)替换为显式白名单形式,例如:unserialize($data, ['allowed_classes' => ['App\Model\Order', 'DateTime']]) - 业务不依赖对象反序列化时,可设为
false(仅允许数组/标量),上线前务必验证功能无异常 - 严禁将
think\Model、think\Cache等框架内置类加入白名单——它们是 POP 链主力输出类 - 空数组
[]或['__PHP_Incomplete_Class']等同于未设限,毫无防护作用
禁用 Phar 协议与高危流封装器
Phar 反序列化仍是高频利用路径,尤其通过 phar://xxx.jpg/exploit.phar 触发:
立即学习“PHP免费学习笔记(深入)”;
- 确保
php.ini中phar.readonly = On(默认开启,但需检查是否被手动关闭) - 设置
allow_url_include = Off - 在
disable_functions中加入unserialize、file_put_contents、system、exec、shell_exec、passthru - Nginx 层添加拦截规则:
if ($request_uri ~* "phar://") { return 403; }
用 JSON 或 MessagePack 彻底替代
绝大多数场景下,不需要 `serialize/unserialize`:
- JSON 天然不触发魔术方法,PHP 8.1 支持
JSON_THROW_ON_ERROR,错误更明确 - 改造示例:把
serialize($_SESSION)存 Redis → 改为json_encode($_SESSION);读取时用json_decode($raw, true) - 对性能敏感场景,可用 ext-msgpack(MessagePack 扩展):二进制格式、无魔术方法风险、PHP 8.1 兼容良好
- 仅当必须保留对象行为、继承关系或资源句柄时才保留 serialize,且必须配合白名单 + 输入签名



















