php反序列化存在安全风险,需严格校验输入;serialize()将变量转为字符串,unserialize()还原变量并可能调用__wakeup()等魔术方法;推荐用json替代以避免对象实例化风险,并通过白名单限制允许类名。

如果PHP应用中存在反序列化操作,且传入的序列化字符串未经过严格校验,则可能触发不安全的反序列化行为。以下是PHP变量反序列化的基础操作说明:
一、理解serialize()与unserialize()函数作用
PHP内置的serialize()函数将变量转换为可存储或传输的字符串格式;unserialize()函数则执行逆向操作,将该字符串还原为原始变量结构。此过程依赖字符串中精确编码的类型标识与数据长度,任何格式偏差均会导致解析失败或异常行为。
1、定义一个包含数组和对象的变量:
$data = ['name' => 'Alice', 'age' => 30, 'scores' => [85, 92, 78]];
2、调用serialize()生成序列化字符串:
$serialized = serialize($data);
立即学习“PHP免费学习笔记(深入)”;
3、输出结果示例:
a:3:{s:4:"name";s:5:"Alice";s:3:"age";i:30;s:6:"scores";a:3:{i:0;i:85;i:1;i:92;i:2;i:78;}}
二、使用unserialize()还原变量
unserialize()函数接收合法的序列化字符串作为参数,按PHP内部规则重建原始变量结构,并返回对应类型的值。该函数不执行代码,但若字符串中包含对象类名且该类已定义,则会实例化对象并调用__wakeup()方法(如存在)。
1、将上一步得到的$serialized赋值给新变量:
$str = 'a:3:{s:4:"name";s:5:"Alice";s:3:"age";i:30;s:6:"scores";a:3:{i:0;i:85;i:1;i:92;i:2;i:78;}}';
2、执行反序列化:
$restored = unserialize($str);
3、验证还原结果:
var_dump($restored);
三、处理含自定义类的对象反序列化
当序列化字符串中包含对象时,unserialize()需确保对应类已加载,否则抛出致命错误。若类中定义了__unserialize()(PHP 8.1+)或__wakeup()方法,这些魔术方法将在反序列化完成后自动调用。
1、声明一个具有__wakeup()方法的类:
class User { public $username; public function __wakeup() { $this->username = strtoupper($this->username); } }
2、序列化该类实例:
$user = new User(); $user->username = 'bob'; $s = serialize($user);
3、反序列化后检查属性变化:
$u = unserialize($s); echo $u->username; // 输出BOB
四、使用JSON替代方案进行安全数据交换
对于仅需传输简单数据结构的场景,推荐使用json_encode()与json_decode()代替serialize/unserialize,因其不支持对象实例化、无魔术方法调用风险,且跨语言兼容性更强。
1、将数组转为JSON字符串:
$json = json_encode(['id' => 123, 'active' => true]);
2、反解JSON字符串为关联数组:
$arr = json_decode($json, true);
3、确认结果类型与内容:
var_dump($arr['id']); // 输出123
五、检测并防止不安全反序列化
在接收外部输入(如cookie、POST字段、文件内容)用于unserialize()前,必须验证其来源可信性与格式合法性。可采用白名单机制限制允许反序列化的类名,或改用更安全的数据格式。
1、检查输入是否为空或非字符串:
if (!is_string($input) || empty($input)) { die('Invalid input'); }
2、预设允许反序列化的类名列表:
$allowed_classes = ['User', 'Config'];
3、使用unserialize()的第二个参数(PHP 7.4+)限定类名范围:
$data = unserialize($input, ['allowed_classes' => $allowed_classes]);











