反序列化是将存储或传输中的数据转换回程序中的对象或数据结构的过程。然而,不安全的反序列化可能导致严重的安全性问题,尤其是在处理来自不可信源的数据时。本文将介绍反序列化的背景知识,提供一些不正确的反序列化引起的安全性问题的示例,并讨论如何防范这些问题。
提问¶
问题1:什么是反序列化?为什么在处理不可信数据时需要特别小心?
问题2:如何利用反序列化漏洞进行攻击?
问题3:列举两种防范不安全反序列化的方法。
课程单元¶
背景知识介绍
示例一:PHP对象注入
示例二:PHP魔术方法注入
示例三:PHP反射对象注入
示例四:PHP命令执行
如何防范
深入学习
1、背景知识介绍¶
反序列化是将序列化后的数据(通常是二进制或文本格式)转换回原始对象的过程。序列化和反序列化广泛应用于数据存储、远程通信和跨语言的数据交换等领域。然而,反序列化的不安全实现可能导致攻击者执行任意代码、访问敏感数据或破坏系统稳定性。
2、示例一:PHP对象注入¶
有问题的代码示例
<?php
class User {
public $username;
public $isAdmin = false;
}
$serializedData = $_GET['data'];
$user = unserialize($serializedData);
if ($user->isAdmin) {
echo "Welcome, admin!";
} else {
echo "Welcome, user!";
}
攻击者可以通过传递恶意的序列化数据来提升权限。例如,攻击者构造这样的攻击代码:
<?php
$data = '0:4:"User":2:{s:8:"username";s:5:"guest";s:7:"isAdmin";b:1;}';
echo urlencode($data);
将这部分的输出构造成如下这样一个url,攻击者通过访问这个地址,就可以欺骗系统认为他们是管理员用户,从而获得未经授权的管理员功能访问权限。
http://example.com/vulnerable.php?data=0%3A4%3A%22User%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A5%3A%22guest%22%3Bs%3A7%3A%22isAdmin%22%3Bb%3A1%3B%7D
3、示例二:PHP魔术方法注入¶
有问题的代码示例
<?php
class FileManager {
public $file;
public function __destruct() {
if (file_exits($this->file)) {
unlink($this->file);
}
}
}
$serializedData = $_GET['data'];
$fileManager = unserialize($serializedData);
攻击者可以利用反序列化对象来删除任意文件。例如,攻击者构造这样的攻击代码:
<?php
$data = '0:10:"FileManager":1:{s:4:"file";s:12:"/etc/passwd";}';
echo urlencode($data);
将这部分的输出构造成如下这样一个url,攻击者通过访问这个地址,成功删除了 /etc/passwd 文件,可能导致系统不稳定或拒绝服务。
http://example.com/vulnerable.php?data=0%3A10%3A%22FileManager%22%3A1%3A%7Bs%3A4%3A%22file%22%3Bs%3A12%3A%22%2Fetc%2Fpasswd%22%3B%7D
4、示例三:PHP反射对象注入¶
有问题的代码示例
<?php
class Example {
public $name;
public $value;
public function __toString() {
return $this->name . ": " . $this->value;
}
}
$serializedData = $_GET['data'];
$object = unserialize($serializedData);
echo $object;
攻击者可以利用反射对象来注入恶意代码。例如,攻击者构造这样的攻击代码:
<?php
$data = '0:8:"Example":2:{s:4:"name";s:6:"system";s:5:"value";s:12:"ls /var/www";}';
echo urlencode($data);
将这部分的输出构造成如下这样一个url,攻击者通过通过注入命令,攻击者可以执行任意系统命令,可能导致未经授权的系统文件和数据访问。
http://example.com/vulnerable.php?data=0%3A8%3A%22Example%22%3A2%3A%7Bs%3A4%3A%22name%22%3Bs%3A6%3A%22system%22%3Bs%3A5%3A%22value%22%3Bs%3A12%3A%22ls%20%2Fvar%2Fwww%22%3B%7D
5、示例四:PHP命令执行¶
有问题的代码示例
<?php
class Command {
public $cmd;
public function __destruct() {
system($this->cmd);
}
}
$serializedData = $_GET['data'];
$command = unserialize($serializedData);
攻击者可以利用反序列化对象来执行任意命令。例如,攻击者构造这样的攻击代码:
<?php
$data = '0:7:"Command":1:{s:3:"cmd";s:12:"rm -rf /var";}';
echo urlencode($data);
将这部分的输出构造成如下这样一个url,攻击者可以执行删除 /var 目录的命令,可能导致重大数据丢失和系统中断。
http://example.com/vulnerable.php?data=0%3A7%3A%22Command%22%3A1%3A%7Bs%3A3%3A%22cmd%22%3Bs%3A12%3A%22rm%20-rf%20%2Fvar%22%3B%7D
6、如何防范¶
在PHP中使用unserialize函数时,可以通过传递一个选项数组来限制允许反序列化的类,这样可以有效防止不受信任的数据导致的安全问题。例如,[‘allowed_classes’ => false]选项可以确保只有简单的数据类型可以被反序列化,而不包含任何类实例。这种方法通过减少潜在的攻击面,使反序列化过程更加安全。
6.1. 修复示例一:PHP对象注入¶
修复后的安全代码:
<?php
class User {
public $username;
public $isAdmin = false;
}
$serializedData = $_GET['data'];
$user = unserialize($serializedData, ['allowed_classes' => false]);
if ($user instanceof User && $user->isAdmin) {
echo "Welcome, admin!";
} else {
echo "Welcome, user!";
}
由于unserialize函数限制了允许反序列化的类,恶意数据无法创建User类实例,因此攻击失败。
6.2. 修复示例二:PHP魔术方法注入¶
修复后的安全代码:
<?php
class FileManager {
public $file;
public function __destruct() {
if (file_exits($this->file)) {
unlink($this->file);
}
}
}
$serializedData = $_GET['data'];
$fileManager = unserialize($serializedData, ['allowed_classes' => ['FileManager']]);
由于unserialize函数限制只允许FileManager类,恶意数据中的非FileManager类实例无法被反序列化,避免了文件删除的风险。
6.3. 修复示例三:PHP反射对象注入¶
修复后的安全代码:
<?php
class Example {
public $name;
public $value;
public function __toString() {
return $this->name . ": " . $this->value;
}
}
$serializedData = $_GET['data'];
$object = unserialize($serializedData, ['allowed_classes' => ['Example']]);
echo $object;
由于unserialize函数限制只允许Example类,恶意数据中的其他类实例无法被反序列化,避免了恶意命令的执行。
6.4. 修复示例四:PHP命令执行¶
修复后的安全代码:
<?php
class Command {
public $cmd;
public function __destruct() {
if($this->cmd && preg_match('/^[a-zA-Z0-9-]+$/', $this->cmd)){
system($this->cmd);
}
}
}
$serializedData = $_GET['data'];
$command = unserialize($serializedData, ['allowed_classes' => ['Example']]);
由于unserialize函数限制只允许Command类,且通过正则表达式检查命令,恶意命令无法被执行,避免了系统中断的风险。
7、深入学习¶
序列化和反序列化的替代方案:学习使用JSON或XML等更安全的数据格式进行数据传输和存储。
输入验证和输出编码:强化输入验证和输出编码,防止注入攻击。
使用安全库和框架:选择使用经过安全审查的库和框架,它们通常会有更好的防护措施。
深度学习安全性:阅读OWASP指南,了解更多关于反序列化漏洞和其他安全问题的详细信息。