You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何PHP文档禁止向unserialize()传入不可信用户输入(即使allowed_classes=false)

为什么设置allowed_classes=false后,unserialize()仍不能处理不可信用户数据?

你提到的点没错——当allowed_classes=true或不设置选项时,不可信数据会带来对象实例化的风险,比如触发魔术方法(__wakeup、__destruct)导致代码执行。但allowed_classes=false并非绝对安全,核心原因有这几个:

1. 拒绝服务(DoS)攻击风险

恶意构造的序列化字符串能直接拖垮服务器,和是否实例化对象无关:

  • 比如嵌套深度达到数千层的数组,unserialize解析时会消耗大量栈内存,直接导致栈溢出;
  • 或者包含重复的超大数据块,让PHP进程瞬间耗尽内存,引发OOM(内存不足)崩溃。
    这类攻击不需要任何对象实例化,只要unserialize开始解析字符串就会触发。

2. 敏感信息泄露

当allowed_classes=false时,遇到对象类型的序列化数据,PHP会将其转为__PHP_Incomplete_Class实例,这个实例会保留原对象的类名和所有属性值。如果原序列化数据里包含敏感信息(比如数据库密码、用户隐私数据),这些内容会直接暴露在__PHP_Incomplete_Class的属性中,被攻击者获取。

3. 底层内存/资源漏洞

历史上PHP多个版本的unserialize函数存在底层漏洞,比如堆溢出、内存破坏等,这类漏洞的利用不需要实例化任何对象——只要构造特定格式的序列化字符串,就能触发内存错误,进而执行恶意代码或者破坏系统稳定性。即使allowed_classes=false,这些底层逻辑的漏洞依然存在。

4. 特殊内置类型的意外行为

部分PHP内置的特殊类型(比如资源句柄、闭包)在unserialize时,即使allowed_classes=false,也可能触发非预期的资源操作。比如旧版本中,某些资源类型的序列化数据被解析时,可能导致已打开的文件/网络连接被意外操作,或者资源句柄泄露。

总结来说,allowed_classes=false只是规避了对象实例化带来的代码执行风险,但unserialize本身的解析过程、数据结构处理依然存在被利用的空间。处理不可信数据的安全做法是:永远不要用unserialize处理用户输入,改用JSON、MsgPack等安全的序列化格式。

内容的提问来源于stack exchange,提问作者user2543740

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 23:35:06