【反序列化漏洞-01】序列化与反序列化简介
目录
- 1 背景
- 2 序列化与反序列化的定义
- 3 作用及优点
- 4 例子:测试php代码中序列化与反序列化执行过程
- 4.1 测试环境
- 4.2 测试序列化过程
- 4.3 测试反序列化过程
- 5 例子:SessionID在php中的序列化与反序列化
- 5.1 SessionID序列化
- 5.2 SessionID反序列化
- 6 总结
- 参考文章
1 背景
(1)在PHP中,每个类的定义都以关键字 class 开头,后面跟着类名,后面跟着一对花括号,里面包含有类的属性与方法的定义。
(2)一个类可以包含有属于自己的属性(常量,变量)和方法(函数)。
(3)由于类的实例化对象比较抽象,不方便用于传输和存储。

tips(类与对象):
- 类为class,对象是object;举个例子,车为一个大类,大类再分小类如自行车、卡车;而具体的某台车为一个对象。
2 序列化与反序列化的定义
序列化与反序列化过程在php、python等多种语言中普遍存在。
- 序列化:程序将对象状态转换为可存储或传输的字节序列的过程(即将对象状态转换为可存储或可传输的过程)
- 反序列化:程序把存储或传输的字节序列恢复为对象的过程。
- 核心思想:对象状态的保存和重建。
PHP中的序列化与反序列化,基本都是围绕serialize()和unserialize()两个函数展开的。
3 作用及优点
序列化的意义:在传递和保存对象时,为保证对象的完整性和可传递性,程序将对象转换为有序字节流,以保存在本地文件中,并且可以以特定的格式在进程之间跨平台、安全的进行通信。比如从java平台传递到php平台。
反序列化的意义:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
序列化的优点:
- 将对象转为字节流存储到硬盘上(实际上是存放在数据库,一般是redis数据库-键值对数据库),当JVM停机的话,字节流还会在硬盘上默默等待,等待下一次JVM的启动,把序列化的对象,通过反序列化为原来的对象。
- 序列化后的二进制序列能够减少存储空间(永久性保存对象)。
- 序列化成字节流形式的对象可以进行网络传输。
- 通过序列化可以在进程间传递对象。
tips:
实际上用redis数据库作为缓存,一般用于存储序列化后的字符串,待字符串需要使用时,再反序列化为对象,方便调用。
4 例子:测试php代码中序列化与反序列化执行过程
4.1 测试环境
服务器:在虚拟机中安装win2008及phpstudy,参考《【语言环境】WAMP环境部署及优化—以win2008R2SP1为操作系统》。
客户端:真实机浏览器。
4.2 测试序列化过程
(1)在服务器网站根目录下新建一个文件夹serialize_unserialize,再在该文件夹下新建一个txt文件,输入以下内容,并重命名为serialize.php。
<meta charset = "utf-8">
<?php
//定义一个stu类,类中有4个属性,暂未定义方法。
class stu{public $name;public $sex;public $age;public $score;
}//创建对象1
$stu1=new stu();
$stu1->name="gzz";
$stu1->sex=true;
$stu1->age=18;
$stu1->score=66;//创建对象2
$stu2=new stu();
$stu2->name="dqq";
$stu2->sex=false;
$stu2->age=18;
$stu2->score=96;//输出gzz和dqq的成绩
echo $stu1->name."'s score=".$stu1->score;
echo "
";
echo $stu2->name."'s score=".$stu2->score;//用var_dump输出对象
echo "
";
var_dump($stu1);
echo "
";
var_dump($stu2);//对对象进行序列化并输出
echo "
";
echo "序列化后采用echo输出
";
echo serialize($stu1);?>
(2)真实机浏览器访问该网页,显示如下。可以看到对象被序列化成字符串:,其中:
object(stu)#1 (4) { ["name"]=> string(3) "gzz" ["sex"]=> bool(true) ["age"]=> int(18) ["score"]=> int(66) }
①object表示对象;(stu)表示对象所属类, (4) 表示有4个属性O:3:"stu":4:{s:4:"name";s:3:"gzz";s:3:"sex";b:1;s:3:"age";i:18;s:5:"score";i:66;}
①O表示该字符串对对象;3表示该对象名有3个字符;stu表示对象名;4表示有4个属性;
②花括号内每两个分号表示一个属性的键值对。

4.3 测试反序列化过程
(1)复制上述serialize.php文件,并重命名为unserialize.php内容修改如下:
<meta charset = "utf-8">
<?php
//定义一个stu类,类中有4个属性,暂未定义方法。
class stu{public $name;public $sex;public $age;public $score;
}//接收来自输入或者前文生成的字符串。
$obj=$_GET['obj'];//反序列化
$stu1 = unserialize($obj);//采用var_dump输出
echo "采用var_dump输出
";
var_dump($stu1);
echo '
';//对对象进行序列化并输出
echo "序列化后采用echo输出
";
echo serialize($stu1);?>
(2)真实机浏览器访问该网页并传入参数obj,访问参数为?obj=O:3:%22stu%22:4:{s:4:%22name%22;s:3:%22gzz%22;s:3:%22sex%22;b:1;s:3:%22age%22;i:18;s:5:%22score%22;i:66;},网页显示结果如下。可以看到反序列后后成功生成对象。

5 例子:SessionID在php中的序列化与反序列化
5.1 SessionID序列化
以PHP语言为例,简单介绍Session ID序列化的过程。
(1)在第4行中,odbc_connect函数,执行成功则返回connection ID函数,失败则返回false。输入参数依次为数据库名、用户名、密码、其他参数。
(1)在第5行中,odbc_prepare函数,如果成功准备 SQL 命令,则返回 ODBC 结果标识符; 出错时返回 false。
(1)在第6行,serialize()函数将 session_data 进行序列化;随后,array()生成一个数组,数组的第一个元素是序列化后的字节流,第二个元素是变量。
(1)在第7行的判断条件中,odbc_execute()函数将准备好的数组传入到准备好的SQL语句中执行,进行数据库中的对应数据的更新。如果执行失败,则执行 if 函数体。
<?php
// $session_data 是包含了当前用户 session 信息的多维数组。
// 我们使用 serialize() 在请求结束之前将其存储到数据库中。
$conn = odbc_connect ("webdb", "php", "chicken");
$stmt = odbc_prepare ($conn, "UPDATE sessions SET data = ? WHERE id = ?");
$sqldata = array (serialize($session_data), $PHP_AUTH_USER);
if (!odbc_execute ($stmt, &$sqldata)) {$stmt = odbc_prepare($conn,"INSERT INTO sessions (id, data) VALUES(?, ?)");if (!odbc_execute($stmt, &$sqldata)) {/* 出错 */}
}
?>
5.2 SessionID反序列化
以PHP语言为例,简单介绍Session ID反序列化的过程,是上述例子的延续。
(1)在第6行,使用array()函数将超全局变量$_SERVER的属性PHP_AUTH_USER内容定义为数组。
(1)在第7行中,使用odbc_execute()函数从数据库中找到对应user的SessionID;odbc_fetch_into()返回结果中的列数,错误时为返回false。
(1)在第12行中,对从数据库中取得的SessionID进行反序列化。
<?php
// 这里,我们使用 unserialize() 装载来自数据库的 $session_data 数组中的会话数据。
// 此例是描述 serialize() 的那个例子的补充。
$conn = odbc_connect("webdb", "php", "chicken");
$stmt = odbc_prepare($conn, "SELECT data FROM sessions WHERE id = ?");
$sqldata = array($_SERVER['PHP_AUTH_USER']);
if (!odbc_execute($stmt, $sqldata) || !odbc_fetch_into($stmt, $tmp)) {// 如果执行出错或返回错误,则初始化为空数组$session_data = array();
} else {// 现在我们需要的是 $tmp[0] 中已序列化的数据。$session_data = unserialize($tmp[0]);if (!is_array($session_data)) {// 出错,初始化为空数组$session_data = array();}
}
?>
6 总结
(1)了解序列化与反序列化的作用;
(1)掌握PHP中序列化与反序列化的使用方法。
参考文章
[1]《序列化和反序列化的详解》
[2]《PHP类与对象基本概念》初学者建议看一下PHP官方手册对类的应用方法。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
