PHP 7.4.33 原生支持 unserialize() 的 allowed_classes 参数,需显式传入白名单数组或 false 以禁用对象;严禁列入含 POP 链的框架类,须硬编码、配合输入校验与日志监控,并优先迁移到 JSON 等更安全方案。

PHP 7.4.33 已原生支持 unserialize() 的 allowed_classes 参数,这是防范反序列化漏洞最直接、最有效的手段之一。它不依赖 PHP 配置项(如 unserialize_callback_func),而是通过函数调用时显式声明白名单,从逻辑层切断非法类的实例化。
在代码中正确使用 allowed_classes 参数
必须将白名单作为第二个参数传入 unserialize(),不能靠 php.ini 或运行时配置自动生效:
- 只允许特定类:
unserialize($data, ['allowed_classes' => ['Config', 'CacheItem']]) - 完全禁止对象(仅基础类型):
unserialize($data, ['allowed_classes' => false]) - 空数组
[]或省略该参数,等同于allowed_classes => true,即放行所有类——这等于无防护
白名单设计的关键原则
白名单不是“哪些类能用”,而是“哪些类绝对可信且必要”:
- 只列入业务中明确需要反序列化的自定义安全类,例如纯数据容器(DTO)、配置类等
-
严禁加入框架核心类:如
think\Model、Illuminate\Http\Request、Symfony\Component\Process\Process等——它们自带 POP 链 gadget,是攻击者首选目标 - 避免通配符或动态拼接类名,白名单必须是硬编码的字符串数组
配合输入来源做严格校验
allowed_classes 不能替代输入验证,需叠加防护:
立即学习“PHP免费学习笔记(深入)”;
- 若反序列化数据来自 Cookie、GET/POST、Header 或文件上传,先校验格式(如是否以
a:、O:、s:开头)和长度,非预期结构直接拒绝 - 对已知只含数组/标量的场景(如用户配置缓存),强制设为
false,让恶意O:对象自动转为__php_incomplete_class,后续调用会报错而非执行 - 日志中记录被拦截的反序列化尝试(如检测到
O:但allowed_classes === false),便于发现扫描行为
替代方案建议(长期演进)
即便启用 allowed_classes,也应规划降级路径:
- 优先改用
json_encode()/json_decode()处理结构化数据,天然不支持对象、无魔术方法风险 - 如需保留对象语义,可封装为 DTO + 显式构造,避免依赖反序列化重建逻辑
- 禁用
phar://协议(在php.ini中设置phar.readonly = On并移除phar扩展),防止 Phar 文件绕过白名单



















