最直接有效的方式是彻底避免在不可信输入上使用 unserialize();应改用 json_decode($data, true),或启用 PHP 7.4+ 的 allowed_classes 白名单,同时关闭 phar.readonly 和 allow_url_include,并全局排查、升级框架。

最直接有效的方式是彻底避免在不可信输入上使用 unserialize()。它本身不是“坏函数”,但一旦参数来自用户(如 $_GET、$_COOKIE、缓存内容、日志字段),就极易触发魔术方法,形成 POP 链导致任意文件操作、命令执行甚至 RCE。
替换为更安全的序列化方案
绝大多数业务场景中,不需要还原 PHP 对象,只需传输结构化数据:
- 用
json_decode($data, true)替代unserialize();JSON 只解析为数组或标量,不调用任何魔术方法,天然免疫反序列化漏洞 - 确保前后端/模块间约定使用 JSON 格式,包括缓存存储、API 响应、Cookie 数据等
- Laravel 的
$casts = ['meta' => 'array']、ThinkPHP 的json类型自动处理,都基于json_decode,可放心使用
若必须保留 unserialize,启用 allowed_classes 白名单
PHP 7.4+ 支持第二个参数,强制限定可反序列化的类名:
- 写法:
unserialize($input, ['allowed_classes' => ['SafeConfig', 'CacheItem']]) - 传
false表示只允许基础类型(数组、字符串、整数等),完全禁止对象还原 - 切勿将框架核心类(如
think\Model、think\Request)加入白名单——它们常是 POP 链起点 - 空数组
[]或未设置该参数,等同于无防护
关闭危险协议与运行时拦截
Phar 反序列化是常见绕过手段,需从 PHP 配置和 Web 层双重封堵:
立即学习“PHP免费学习笔记(深入)”;
- 修改
php.ini:phar.readonly = On(默认值,旧环境常被手动关)、allow_url_include = Off - Nginx 中添加规则拦截可疑请求:
if ($request_uri ~* "phar://") { return 403; } - 设置
unserialize_callback_func回调函数,在遇到未注册类时直接中止,避免静默失败
代码层与工程规范加固
防御要落在日常开发习惯里,而非仅靠配置:
- 全局搜索项目(含
vendor/)中的unserialize(,逐个确认是否必要;旧版 SDK、缓存驱动、日志解析模块是高危重灾区 - 禁用调试模式(
app_debug => false),防止错误信息泄露类路径,降低攻击者构造链难度 - 所有接收用户输入的位置(
input()、$_POST、Cookie 解析中间件)禁止调用unserialize - 升级框架:ThinkPHP 5.1.40+、6.3+ 已修复多条主流 POP 链;Laravel 无需特别处理
Crypt::decrypt,但绝不可在其后叠加unserialize



















