直接用 unserialize() 批量处理文件极危险,因恶意字符串可触发 __wakeup() 等魔术方法导致 RCE;安全做法是禁用类加载、设 allowed_classes => false,或改用 igbinary_unserialize()/json_decode()(需格式匹配)。

为什么直接用 unserialize() 批量处理文件很危险
因为 PHP 的 unserialize() 在遇到恶意构造的字符串时,会触发任意代码执行(如通过 __wakeup()、__destruct() 等魔术方法)。批量反序列化一堆未知来源的文件,等于主动打开 RCE 大门。哪怕只是“简单看看内容”,只要文件不可信,就绝不该用原生 unserialize()。
用 igbinary_unserialize() 或 json_decode() 替代的前提
只有当这批文件确定是用 igbinary_serialize() 生成的,才能用 igbinary_unserialize() ——它不解析 PHP 魔术方法,相对安全;而如果原始数据其实是 PHP 数组但被人工转成了类似 serialize 格式(比如用 var_export() 存的),那更稳妥的做法是先统一转成 JSON 再读:
$content = file_get_contents($file);
$data = json_decode(str_replace(['array (', ')', '=>'], ['[', ']', ':'], $content), true);但这只适用于结构极简、无对象、无资源句柄的场景。
真要解析 PHP 原生 serialize() 字符串,必须禁用类自动加载和反序列化回调
核心是切断对象实例化链路:
- 设置
unserialize_callback_func为null或空函数 - 确保
__autoload()和spl_autoload_register()不会响应未知类名 - 用
unserialize($str, ['allowed_classes' => false])(PHP 7.4+)彻底禁止对象创建
$str = file_get_contents('data.ser');
$data = @unserialize($str, ['allowed_classes' => false]);
if ($data === false) {
echo "反序列化失败或含非法结构\n";
}批量处理时最容易漏掉的兼容性细节
不同 PHP 版本对 serialize 格式容忍度不同:
- PHP 8.1+ 默认拒绝含
R:引用符号的字符串(防止引用绕过) - 含
O:(对象)、C:(自定义类)的串在allowed_classes => false下直接返回false,不是抛异常 - 二进制 serialize 数据(如用
mb_convert_encoding()转过编码)会导致解析失败,务必用file_get_contents()原样读取
if (substr($str, 0, 2) !== 'a:' && substr($str, 0, 2) !== 's:') { /* 跳过非数组/字符串开头的可疑串 */ }真正安全的批量反序列化,本质是放弃执行语义,只提取数据结构。一旦需要还原对象行为,就得逐个审查类定义、关闭自动加载、沙箱隔离——这已经超出“简单”范畴了。



















