最有效防御是反序列化前加白名单过滤;PHP 7.4+ 支持 unserialize() 的 allowed_classes 参数,须显式指定允许类(如 ['Cart', 'OrderItem'] 或 [false]),禁用危险魔术方法、PHAR 协议,并优先用 JSON 替代 unserialize()。

PHP 本身没有“序列化参数”这一全局配置项,serialize() 和 unserialize() 是纯函数,不通过 ini 设置或运行时参数控制其基础行为。但你在实际使用中可干预的环节主要有三类:序列化前的数据处理、反序列化时的安全选项、以及会话层的序列化处理器选择。下面分场景说明关键设置点:
如何控制序列化前的对象状态
对象在被 serialize() 处理前,PHP 会自动检查并调用特定魔术方法:
- 若定义了
__sleep(),则只序列化该方法返回的属性名数组; - 若未定义
__sleep()但定义了__serialize()(PHP 8.0+),则按其返回的键值对序列化; - 这两个方法可用于排除敏感字段、关闭连接、清理资源等。
例如:
class User {
public $name;
private $token;
public function __sleep() {
return ['name']; // token 不会被序列化
}
}如何限制反序列化的类范围(关键安全设置)
PHP 7.4+ 的 unserialize() 支持 $options 参数,可指定白名单类名,防止任意类实例化导致的反序列化漏洞:
立即学习“PHP免费学习笔记(深入)”;
$data = 'O:3:"Log":1:{s:4:"file";s:9:"shell.php";}';
$allowed = ['User', 'Config'];
$restored = unserialize($data, ['allowed_classes' => $allowed]);
// 若 Log 不在白名单中,抛出 Error⚠️ 不传此选项或设为 true(默认)等于开放所有类,风险极高。
如何切换会话数据的序列化方式
当使用 $_SESSION 时,底层序列化由 session.serialize_handler 配置决定,可在 php.ini 或运行时设置:
; php.ini 中设置 session.serialize_handler = php_serialize
或代码中:
ini_set('session.serialize_handler', 'php_serialize');常用值说明:
-
php:旧格式,存在键名注入风险(如|分隔符问题); -
php_serialize:统一用serialize()格式,更安全,推荐; -
php_binary:二进制格式,兼容性差,少用。
不复杂但容易忽略。



















