PHP反序列化RCE核心是切断不可信输入进入unserialize()的路径:第一步停用所有unserialize()入口,替换为json_decode;第二步强制启用allowed_classes白名单且仅限必要基础类;第三步封禁phar://等危险协议;第四步精准升级框架并验证补丁有效性。

PHP反序列化漏洞引发远程代码执行(RCE),核心问题不是“怎么修某个函数”,而是**彻底切断不可信数据进入unserialize()的路径**。只要用户可控输入被直接反序列化,且存在可用POP链,RCE就极大概率成立——这不是配置问题,是架构级风险。
第一步:停用所有unserialize()入口
这是最直接、最有效的动作。不要尝试加固,先移除。
- 全局搜索unserialize(,重点检查:$_GET、$_POST、$_COOKIE、$_SESSION、缓存读取(如Memcached::get)、日志解析、文件上传临时路径处理
- ThinkPHP项目中特别注意:
think\cache\driver\File->read()、think\session\driver\Memcache->read()、自定义控制器里调试用的unserialize($_POST['data']) - 全部替换为
json_decode($input, true),并确保后续逻辑不依赖对象实例(JSON只返回数组/标量)
第二步:若真无法立即移除,必须启用allowed_classes白名单
仅限PHP 7.4+,且白名单必须严格、最小化。
- 禁止写
['allowed_classes' => true]或空数组[]——这等于没设限 - 写
['allowed_classes' => false]表示只允许基础类型(数组、字符串、整数等),不恢复任何类,最安全 - 如业务强依赖某几个类(如
DateTime、stdClass),则明确列出:['allowed_classes' => ['DateTime', 'stdClass']] -
绝对不要把
think\Model、think\Cache、Psr6Cache等框架类放进白名单——它们是POP链主力
第三步:封死Phar协议与危险流封装器
很多RCE根本不需要调用unserialize(),一个file_exists('phar://xxx')就能触发。
立即学习“PHP免费学习笔记(深入)”;
- 确认
php.ini中:phar.readonly = On(默认开启,但旧环境常被手动关掉) - 禁用危险协议:
allow_url_include = Off,并在disable_functions中加入unserialize,file_put_contents,system,exec,shell_exec,passthru - Nginx/Apache层加拦截规则,例如Nginx中:
if ($request_uri ~* "phar://") { return 403; }
第四步:升级框架并验证补丁有效性
ThinkPHP等主流框架已修复多个高危反序列化链,但版本对应关系必须精确。
- CVE-2024-44902(影响v6.1.3–v8.0.4):升级至
thinkphp:^8.0.5或^6.1.12 - CVE-2022-38352(影响v6.0.0–v6.0.13):必须升至
v6.0.14+ - 升级后检查关键文件是否更新,例如
vendor/topthink/framework/src/think/route/ResourceRegister.php中__destruct是否已被移除或校验 - 运行时验证:用已知POC尝试触发,确认返回错误而非命令执行结果



















