反序列化漏洞1-PHP序列化基础概念(0基础超详细)
一.PHP序列化基础概念
首先当我们看到反序列化漏洞这个概念,我们的第一个问题是什么是反序列化?那么我们要知
道什么是反序列化就要知道什么是序列化。
序列化就是可以将一个对象压缩并格式化成字符串,可以将该对象保存下来,以便存储及运
输。那么问题又来了,我们为什么要对对象这么做呢?因为在PHP中对象在你的代码执行过后会自
动销毁。所以你要想将对象保存下来的话就要通过序列化将对象按照固定的格式将对象压缩并格式
化转化成字符串这样就可以将对象保存下来了,其实不进行序列化将对象保存在数据库也是ok的。
很多对象是在用户端产生,而用户没有权限将对象保存在数据库中,所以通过序列化将对象
压缩并格式化成字符串,然后传输给服务器,让服务器去进行保存到数据库。
那么反序列化的概念也就很简单了:就是当我们要用对象时,将序列化的字符串进行还原成
对象。
二.学习序列化要了解的基本内容。
类(Class): 类的定义包含了数据的形式以及对数据的操作。
对象:对象是类的实例。
方法:类中定义的函数。
属性:函数中的变量。
类是由很多个方法组成的,举例:我们有一个查询用户信息的功能点,而查询信息的方法有很
多,我们就把他划为一类,实际上方法也就是我们自定义的函数对于一些功能点。
而对象是指当我们去调用某一个方法时不可能去crtl+c,ctrl+v去使用某一方法。计算机会使用
内存去调用,及当某一个用户去调用某一功能点时,用户电脑内存会创造一个实例也就是对象,对
象中含有所有要调用的方法,然后程序调用的是对象中的方法。
三.PHP序列化函数及序列化过程介绍
serialize() //将一个对象转换成一个字符串
代码示例:
<?php
//创建一个类 Test
class Test
{
//定义 3 个属性,最后序列化后看一下这 3 个属性序列化后的结果。(属性a,b,c)
private $a = "private";
public $b = "public";
protected $c = "protected";
}
//创建一个对象,对象是类的实例。(test就是创建的实例)(new就是创建对象的特征)
$test = new Test();
//序列化 test 这个对象
$data = serialize($test);
//打印序列化后的对象
echo $data;
?>
那么我们来看看序列化后的字符串长什么样子:


我们来观察一下这段序列化后的字符串:
O:4:"Test":3:{s:7:"Testa";s:7:"private";s:1:"b";s:6:"public";s:4:"*c";s:9:"protected";}
字符串解释
括号前
O指的是object(对象)
4指的是Test这个对象有4个字符
Test就是类名称。
3就是指的这个类里面有几个属性,(这里面有a,b,c三个属性)。
括号里
而方括号里的就是对应三个属性的字段了:
s:7:"Testa";s:7:"private"
s:1:"b";s:6:"public"
s:4:"*c";s:9:"protected"
s表示string字符串,前面s:7:"Testa"表示变量的名字,s:7:"private"后面表示变量名的值。
里面的7表示变量名的长为7个字符。为什么Testa是5个字符为什么表示7个,原因是名字中存在不可见字符,在字符左右,private定义Testa是一个私有的变量存在在Test里面。
public类型公用的,b就是一个字符,后面public也就是6个字符。
protected类型是指受保护类型,指的是在这个类及这个子类里面都可以使用,
*c,4个名字长度,很明显不符合,其实是 00*00c,在*左右存在两个不可见字符,而*表示当前类及其子类。
四.反序列化函数及反序列化过程介绍
unserialize() //反序列化
代码示例:
<?php
//创建一个类 Test
class Test
{
//定义 3 个属性,最后序列化后看一下这 3 个属性序列化后的结果。(属性a,b,c)
private $a = "private";
public $b = "public";
protected $c = "protected";
}
//创建一个对象,对象是类的实例。(test就是创建的实例)(new就是创建对象的特征)
$test = new Test();
//序列化 test 这个对象
$data = serialize($test);
//打印序列化后的对象
echo $data;
//反序列化data这个对象
$fjw = unserialize($data);
//打印反序列化后的对象
var_dump($fjw);
?>
我们在源代码后添加了两行。


我们观察反序列化后的代码:
object(Test)#2 (3) {
["a":"Test":private]=>
string(7) "private"
["b"]=>
string(6) "public"
["c":protected]=>
string(9) "protected"
}
与最原始的基本没差别。、
["a":"Test":private]=>
string(7) "private"
["b"]=>
string(6) "public"
["c":protected]=>
string(9) "protected"
}
与最原始的基本没差别。、
注意:因为有不显示空白字符的存在,我们在传输一段字符串的时候不能直接进行传世,因为空白字符无法打字打上去,所以我们通常对字符串进行base64加密后再进行传输。
五.空白字符帮助理解
不理解的话举例:
我们创建一个unserialize.php
这里我们对于空白字符用空格替换,因为要与前面的字符长度表示一致

直接对原字符串进行反序列化:

我么可以看到" Test a"但实际我们的变量名只有一个a,是因为我们这里没法表示空白字符,只能用空格代替表示,所以和我们原来的数据还是有差异的。
所以在传输字符串的时候如果直接传输会存在数据丢失的情况,所以我们通常使用base64加密后再传输就可以避免这种情况。