为什么要序列化
百度百科上关于序列化的定义是,将对象的状态信息转换为可以存储或传输的形式(字符串)的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区(非关系型键值对形式的数据库Redis,与数组类似)。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
在PHP中,每个类的定义都以关键字class开头,后面不仅跟着类名还跟着一对花括号,里面包含有类的属性与方法的定义。
一个类可以包含有属于自己的属性(常量:值变量的值不会改变、变量)和方法(函数)。
由于类的实例化对象比较抽象,不方便用于传输和存储。
tips:类为class,对象是object;举例来说就是,动物为一个大类,大类之后再分小一类如猫猫或者狗狗;而具体的某个动物就为一个对象。一个对象就相当于一个变量,对象是一种语言结构。
简单来说,序列化就是把一个对象变成可以传输的字符串(字符串便于传输,只需要把字符串赋给变量即可)。在传递和保存对象时,为保证对象的完整性和可传递性,程序将对象转换为有序字符串,以保存在本地文件中,可以以特定的格式在进程之间跨平台、安全的进行通信。(比如从java平台传递到php平台)反序列化则根据字符串中保存的对象状态及描述信息,通过反序列化重建对象。
序列化的优点:
将对象转为字节流存储到硬盘上(实际上是存放在数据库,一般是redis数据库-键值对数据库),当JVM停机的话,字节流还会在硬盘上默默等待,等待下一次JVM的启动,把序列化的对象,通过反序列化为原来的对象。
序列化后的二进制序列能够减少存储空间(永久性保存对象)。
序列化成字符串形式的对象可以进行网络传输。
通过序列化可以在进程间传递对象
实际上用Redis数据库作为缓存,一般用于存储序列化后的字符串,待字符串需要使用时,再反序列化为对象,方便调用。
PHP中的序列化与反序列化
反序列化漏洞并不是PHP特有,也存在于Java、Python等语言之中,但其原理基本相通。
PHP反序列化漏洞也叫php对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一旦利用成功就会造成非常危险的后果。
漏洞的形成的根本原因是程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而造成代码执行、getshell等一系列不可控的后果。
序列化与反序列化的定义
序列化:程序将对象状态转换为可存储或传输的字节序列的过程(即对象状态转换为可存储或者可传输的过程){序列化是对象转换为字符串的过程}
反序列化:程序把存储或传输的字节序列恢复为对象的过程。{反序列化则是字符串转化为对象的过程}
如果字符串客户端可控,就会造成web应用反序列化任意对象,在反序列化的过程中会触发一些可以执行的php代码,例如phpinfo
PHP中的序列化与反序列化,基本都是围绕serialize()和unserialize()两个函数展开的。在介绍这两个函数之前,我们可以先看一个简单的例子。
序列化Demo
序列化会将一个抽象的对象转换为字符串。
我们可以写一个Demo来说明序列化的过程,首先创建一个类,代码内容如下:
<?php
class student{
public $name;
public $sex;
public $age;
public $score;
}
?>
类名是student,该类中有四个变量。接下来,我们可以将这个类实例化,也就是创建一个对象(new),并给对象中变量赋值。代码如下:
<?php
// 定义一个student类,类中有四个属性
class student{
public $name;
public $sex;
public $age;
public $score;
}
// 创建对象1
$student1 = new student();
$student1->name = "wyy";
$student1->sex = false;
$student1->age = 20;
$student1->score = 95;
?>
最后我们使用serialize(),将$student1这个对象序列化成一个字符串。这样的字符串就很容易传输和存储了。如下:
<?php
// 定义一个student类,类中有四个属性
class student{
public $name;
public $sex;
public $age;
public $score;
}
// 创建对象1
$student1 = new student();
$student1->name = "wyy";
$student1->sex = false;
$student1->age = 20;
$student1->score = 95;
// 创建对象2
$student2 = new student();
$student2->name = "xcc";
$student2->sex = true;
$student2->age = 25;
$student2->score = 98;
// 输出wyy和xcc的成绩
echo $student1->name."'s score = ".$student1->score;
// 进行换行
echo "<br/>";
echo $student2->name."'s score = ".$student2->score;
// 用var_dump输出对象
echo "<hr/>";
var_dump($student1);
var_dump($student2);
// 对对象进行序列化并输出
echo "<hr>";
echo "序列化后采用echo输出<br>";
echo serialize($student1);
?>
打开浏览器访问该文件,显示如下,可以看到对象被序列化成字符串: