最有效防御是反序列化前加白名单过滤;PHP 7.4+ 支持 unserialize() 的 allowed_classes 参数,须显式指定允许类(如 ['Cart', 'OrderItem'] 或 [false]),禁用危险魔术方法、PHAR 协议,并优先用 JSON 替代 unserialize()。
直接在反序列化前加一层白名单过滤,是最有效、最可控的防御手段。php 7.4+ 原生支持 unserialize() 的 allowed_classes 参数,它能强制限制只允许还原指定类,彻底阻断恶意 gadget 链的载入。
明确启用类白名单机制
不要依赖默认行为或空数组,必须显式传入允许反序列化的类名列表(含 false 表示禁止所有类):
- 只允许基础数据类:用
['__PHP_Incomplete_Class']或更严格的[false],适用于仅需还原数组/标量的场景 - 业务确需还原自定义对象时:列出且仅列出真正需要的类,例如
['Cart', 'OrderItem'],避免通配符或正则表达式 - 若使用
session_start()自动反序列化 session 数据,需配合session.serialize_handler = php_serialize并在读取后手动校验,不可依赖 session 模块自带过滤
拦截非法类名与魔术方法调用
白名单只是第一道门,还需防止攻击者绕过或利用合法类中的危险逻辑:
- 检查目标类是否定义了高风险魔术方法(如
__wakeup()、__destruct()),若非必要,应移除或加固其实现(例如不执行系统命令、不拼接用户输入) - 对反序列化后的对象做运行时扫描:遍历其属性和方法,发现可疑行为(如属性值含
system(、exec(等字符串)立即中止处理 - 禁用
unserialize()的stream_wrapper_register()扩展能力,防止 PHAR 协议触发(需在 php.ini 中设phar.readonly = On)
用安全替代方案重构关键路径
凡是涉及用户可控输入的反序列化,都应优先考虑不用 unserialize():
- 会话数据:改用
json_encode()/json_decode()存储扁平结构,避开对象还原过程 - 缓存或配置传递:统一走 JSON 格式,服务端只解析为数组,不还原为对象
- 必须传输对象语义时:采用带签名的序列化,如先
hash_hmac('sha256', $data, $secret)生成校验值,反序列化前验证签名一致性
结合自动化工具有效落地
人工维护白名单易遗漏,需工具辅助:
- 静态分析:用 PHPStan 或 Psalm 配合自定义规则,扫描所有
unserialize()调用点,标记未设置allowed_classes的位置 - 运行时监控:在统一反序列化封装函数中埋点,记录每次调用的输入来源(如 Cookie、POST)、类名、是否命中白名单,异常行为实时告警
- CI/CD 检查:将白名单完整性纳入构建流程,缺失配置或硬编码
null值即阻断发布

















