最危险的入口点是直接用unserialize()解析用户可控数据,如cookie、GET或POST参数;攻击者可构造恶意payload触发任意代码执行,核心防御原则是绝不反序列化不可信输入,优先改用json_decode()或严格白名单校验。

PHP反序列化最危险的入口点在哪
直接用 unserialize() 解析用户可控数据,就是典型高危操作。比如从 cookie、GET 参数或 POST body 里读到一串字符串,不加校验就喂给 unserialize(),攻击者可以构造恶意 payload 触发任意代码执行——这是 PHP 反序列化漏洞的核心成因。
怎么安全地反序列化用户提交的数据
根本原则:**永远不要对不可信输入调用 unserialize()**。如果必须解析外部数据,优先换用更安全的格式和函数:
- 用
json_decode()替代,前提是前端能配合发 JSON(绝大多数现代场景都可行) - 若协议固定必须用序列化格式(如遗留系统通信),至少做白名单校验:用
unserialize($data, ['allowed_classes' => ['MyRequest', 'MyConfig']]) - 对输入先做 base64 或 hex 编码再传输,服务端解码后仍需走白名单,不能绕过校验
- 避免在
__wakeup()、__destruct()等魔术方法里写敏感逻辑,这些方法会在反序列化过程中自动触发
为什么 igbinary 或 msgpack 也不建议直接用
它们虽比原生 serialize() 更紧凑或更快,但同样存在反序列化时的类加载与魔术方法执行风险。只要支持自定义类还原,且输入不受控,就逃不开类似问题:
-
igbinary_unserialize()默认不限制类名,等价于裸unserialize() -
msgpack_unpack()在启用object_cast且传入类名时,也会触发构造逻辑 - 除非你完全控制两端协议、且明确禁用对象还原(例如只允许数组/标量),否则没本质区别
真要兼容旧 serialize() 数据怎么办
比如读取老数据库里存的 serialize() 字符串,又不能改存储格式,那就必须硬着头皮处理。关键动作只有两个:
立即学习“PHP免费学习笔记(深入)”;
- 确保目标环境里不存在可利用的 gadget 链(比如删掉所有带危险逻辑的第三方库类)
- 强制指定
allowed_classes为false或空数组,让反序列化只生成__PHP_Incomplete_Class对象,再手动提取字段值 - 示例:
unserialize($data, ['allowed_classes' => false])返回的是一个伪对象,属性可用get_object_vars()拿到,但不会调用任何魔术方法
真正麻烦的不是语法怎么写,而是得确认整个代码路径里没人偷偷在某个 __toString() 里拼接了 system() ——这种隐患藏得深,静态扫描都容易漏。



















