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数据:
- php_binary: 格式为
键名长度的ASCII码+键名+序列化的值 - php: 格式为
键名+"|"+序列化的值 - 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;
利用方法:
- 构造恶意序列化字符串:
$obj = new Flag();
$obj->file = "Flag.php";
echo serialize($obj);
输出: O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
- 将此字符串作为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'));
}
利用方法:
- 当php.ini配置为
session.serialize_handler = php_serialize,而代码中使用php处理器时 - 构造特殊的Session数据,利用php处理器以"|"为分隔符的特性
- 可以注入恶意对象,在反序列化时执行任意代码
5. 防御措施
- 不要反序列化不可信数据:避免直接反序列化用户输入
- 使用一致的处理程序:确保Session序列化处理程序在服务器和代码中一致
- 实现对象验证:在反序列化前验证数据
- 使用替代方案:考虑使用JSON等更安全的序列化格式
- 限制魔术方法:谨慎使用或限制魔术方法中的敏感操作
- 更新PHP版本:使用最新PHP版本以获得安全修复
6. 总结
PHP序列化与反序列化机制虽然方便,但不当使用会带来严重安全风险。开发者需要充分理解序列化格式、魔术方法的触发条件以及Session处理机制,才能有效防范相关漏洞。在实际开发中,应尽量避免反序列化用户可控的数据,或对反序列化过程实施严格的安全控制。