序列化(serialize)和反序列化(unserialize)以及__sleep()函数和__wakeup()函数

本文详细介绍了PHP中对象序列化的过程,包括如何使用__sleep()方法指定要序列化的对象属性,以及如何通过__wakeup()方法在反序列化时填充未存储的属性。

序列化数据就是将数据转化成一个基于文本的格式,以便存储。

__sleep()在序列化前决定哪些属性进行序列化,__wakeup()在反序列化时填充任何没有存储的。

__sleep在一个对象序列化前调用,它不接收任何参数,但会返回数组,这里可以放置需要序列化的属性,

比如下面的例子: 

class Customer {
    private $name;
    private $credit_card_number;

    public function setName($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }

    public function setCC($cc) {
        $this->credit_card_number = $cc;
    }

    public function getCC() {
        return $this->credit_card_number;
    }

    public function __sleep() {
        return array(“name”); //只有name会序列化
    }

}

$c = new Customer();
$c->setName(“Stuard”);
$c->setCC(“456789″);

$data = serialize($c).”\n”;
echo $data.”\n”;

Output:
O:8:”Customer”:1:{s:14:” Customer name”;s:5:”Stuard”;} 

上面在序列化前,__sleep中指定了只有name属性会序列化,而creaditcard不会。

而__wakeup则相反,它是在反序列化前触发的,比如下面例子:

class Customer {  
    private $name;  
    private $credit_card_number;
       
    public function setName($name) {  
        $this->name = $name;
    }  
       
    public function getName() {  
        return $this->name;
    }  
       
    public function setCC($cc) {  
        $this->credit_card_number = $cc;
    }  
       
    public function getCC() {  
        return $this->credit_card_number;
    }  
       
    public function __sleep() {  
        return array(“name”);
    }  
       
    public function __wakeup() {  
        if($this->name == “Stuart”) {  
            //重新在数据库中获得   
            $this->credit_card_number = “1234567890123456″;
        }  
    }  
}  
   
$c = new Customer();  
$c->setName(“Stuart”);  
$c->setCC(“1234567890123456″);  

$data = serialize($c).”\n”;  
var_dump(unserialize($data));  
   
Output:  
object(Customer)#2 (2) {  
["name:private"]=>  
string(5) “Stuart”  
["credit_card_number:private"]=>  
string(16) ’1234567890123456’
}

### PHP反序列化与__wakeup方法的使用及潜在安全问题 PHP中的`__wakeup()`方法是一个魔术方法,它在对象被反序列化时自动调用。该方法的主要目的是在反序列化后重新初始化对象可能需要的资源或执行必要的操作。然而,如果`__wakeup()`方法未正确实现或存在逻辑漏洞,则可能导致严重的安全问题。 #### __wakeup方法的基本功能 当一个对象被序列化为字符串后,可以通过`unserialize()`函数将其还原为原始对象。在此过程中,PHP会自动调用对象定义中的`__wakeup()`方法(如果存在)。此方法通常用于恢复对象的状态,例如重新连接数据库、重新加载文件句柄等[^1]。 ```php class Example { public $data = 'default'; public function __wakeup() { // 在反序列化时执行的操作 $this->data = 'restored'; } } $example = new Example(); $serialized = serialize($example); $unserialized = unserialize($serialized); var_dump($unserialized->data); // 输出 "restored" ``` #### 潜在的安全问题 在某些情况下,攻击者可能通过精心构造的输入数据触发反序列化漏洞。如果`__wakeup()`方法中包含敏感操作(如文件写入、命令执行等),并且这些操作依赖于可控制的属性值,则可能导致以下安全问题: 1. **代码执行** 如果`__wakeup()`方法中包含了可以执行系统命令的逻辑,并且这些命令依赖于用户可控的属性值,则可能允许远程代码执行。例如: ```php class Vulnerable { public $cmd; public function __wakeup() { if ($this->cmd) { shell_exec($this->cmd); // 危险操作 } } } $payload = 'O:9:"Vulnerable":1:{s:3:"cmd";s:10:"touch evil";}'; unserialize($payload); // 可能创建一个名为 "evil" 的文件 ``` 2. **逻辑绕过** 攻击者可以通过修改序列化数据中的属性值来绕过某些限制条件。例如,在引用[2]中提到的场景中,攻击者通过调整序列化数据中的成员变量数量,成功绕过了`__wakeup()`方法中的退出逻辑[^2]。 3. **CVE-2016-7124漏洞** CVE-2016-7124是PHP反序列化漏洞的一个典型案例。该漏洞利用了PHP在处理序列化数据时的一个缺陷:即使序列化的成员数大于实际成员数,PHP仍会尝试反序列化对象。这使得攻击者能够绕过`__wakeup()`方法中的保护逻辑,进而触发恶意行为[^3]。 #### 安全防护措施 为了防止因`__wakeup()`方法引发的安全问题,可以采取以下措施: 1. **避免在`__wakeup()`方法中执行敏感操作** 不应在`__wakeup()`方法中执行可能受用户输入影响的高风险操作,例如文件操作或系统命令执行。 2. **验证过滤用户输入** 对所有用户提供的输入进行严格的验证过滤,确保其符合预期格式范围。 3. **使用白名单机制** 仅允许特定类别的对象被反序列化,避免处理未知或不受信任的数据。 4. **升级PHP版本** 确保使用的PHP版本已修复已知的安全漏洞,例如CVE-2016-7124。 5. **禁用反序列化功能** 如果应用程序不需要使用反序列化功能,可以考虑完全禁用相关功能以减少攻击面。 ```php // 示例:禁用反序列化功能 function safe_unserialize($data, $allowed_classes = []) { return @unserialize($data, ['allowed_classes' => $allowed_classes]); } ``` #### 总结 `__wakeup()`方法在PHP反序列化过程中扮演着重要角色,但如果未正确实现,可能导致严重的安全问题。了解其工作原理并采取适当的防护措施,对于保障应用程序的安全性至关重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值