您的位置:

探究 PHP 反序列化漏洞及防范

随着网络技术的快速发展,Web应用也已经变得越来越普遍和重要。然而,由于用户权限系统、输入验证机制和数据过滤不完善等安全问题,Web应用程序很容易遭受攻击。其中,反序列化漏洞是常见并且严重的一类漏洞。本篇文章将针对 PHP 反序列化漏洞进行探讨,从原理、案例、风险分析以及对策等几个方面进行详细的阐述。希望对初学者和从业者们有所帮助。

一、什么是 PHP 反序列化漏洞?

序列化是将数据结构存储到文件或者保存到会话中的一种方法,通过序列化,我们可以将数据结构进行打包,从而可以进行存储和传输。常见的序列化方式有 JSON 和 PHP 的序列化。然而,反序列化则是将打包之后的数据结构解开还原成了一个对象。

由此,反序列化漏洞就很好解释了。攻击者通过构造恶意的序列化数据,然后在目标网站解序列化数据时,跟据攻击者的设置,获得了一定的权限。从而利用该权限来进行一系列攻击。

二、案例分析——ShopGives 反序列化漏洞

//代码示例
class Asset {
    private $id;
    private $thumb;
    private $size;
    private $filetype;
    private function __construct() {}
    private function __sleep() {}
    private function __wakeup() {}
    public static function generateAsset($path) {
        $asset = new Asset();
        $asset->id = 'ABCDEFGH12345678';
        $asset->thumb = base64_encode(file_get_contents($path . '/thumb.jpeg'));
        $asset->size = filesize($path . '/fullsize.jpeg');
        $asset->filetype = mime_content_type($path . '/fullsize.jpeg');
        return $asset;
    }
    public function show() {
        header('Content-Type: ' . $this->filetype);
        echo base64_decode($this->thumb);
    }
}

class Wish {
    public $name;
    public $desc;
    public $item;
    public function __construct($item) {
        $this->name = 'My Wish List';
        $this->desc = 'This is a list of items I want to have!';
        $this->item = $item;
    }
}

if (isset($_COOKIE['wishlist'])) {
    $encoded = $_COOKIE['wishlist'];
    $cleaned = preg_replace('/[^a-zA-Z0-9\/+=]/', '', $encoded);
    $data = base64_decode($cleaned);
    if ($data != "1") {
        $wishlist = unserialize($data);
    }
}

上述代码是 ShopGives 原始网站的一个漏洞示例。该网站为用户提供心愿清单的功能,支持将商品加入心愿清单中并且匿名分享给朋友,帮助朋友赠送礼物。在上述示例中,我们可以看到该网站使用了 PHP 的序列化功能,将心愿清单的数据结构序列化到了 cookie 中。其中,我们可以定位出漏洞在文件 CookieHandler.php 的第15行,使用了 PHP 的反序列化函数 unserialize。

攻击者可以利用反序列化漏洞构造一个恶意的数据序列,当管理员解包恶意序列时,攻击者就可以通过该序列控制整个 Web 应用程序的行为。其中,攻击成功之后的表现形式很多样,如突破权限、设置后门、加密勒索等等。

三、风险分析及防范措施

对于反序列化漏洞的风险分析,首先需要强调的是该漏洞属于高危漏洞。一旦被攻击者利用成功,会对整个 Web 应用程序造成致命损害。通过上述案例我们可以看到,一些常用的序列化函数(例如 unserialize)本质上都是将序列化的字符串转化为 PHP 对象,序列化字符串中所包含的所有数据都能直接地反映在 PHP 对象中。这使得攻击者可以通过构造恶意序列来实现危害。反序列化漏洞具有以下的特点:

1. 常见的序列化函数都会把所有数据都反映到 PHP 对象中,攻击者可以构造数据以达到自己的目的;

2. PHP 序列化的数据可以存储或在网络上传输,使得攻击者有较大的可掌握时间并且可以窃取重要的 Cookie;

3. 如有恶意用户操纵对象序列,会使 PHP 反序列化函数调用 PHP 对象的 __wakeup 或 __destruct 方法,导致调用执行的代码暴露在黑客手中。

要防范反序列化漏洞,需要采取措施对 PHP 序列化/反序列化操作进行限制,开发者在实现序列化的时候,也应该注意以下几点:

1. 不使用 unserialize 函数反序列化用户输入的数据;

2. 对开发中使用的元素进行正确的序列化;

3. 对 PHP 已经序列化的数据进行合法性验证,例如反序列化的字符长度、域范围、合法字符等等;

4. 序列化/反序列化安全性审查。

在实践中,最好的解决方法是不使用 PHP 白名单的魔术函数来代替标准魔术方法 __wakeup 和 __destruct。如果在某些情况下需要使用标准魔术函数,则应在类代码中随时注释这些代码。另外,还可以通过使用相对绝对路径的类名来保护应用程序不受攻击。

四、总结

本篇文章详细地介绍了 PHP 反序列化漏洞及防范。我们通过 ShopGives 的案例来深入了解反序列化漏洞的危害,以及背后的原理等重要知识点。作为一个开发人员,了解Web 应用程序的安全漏洞和攻击方式是必不可少的。通过本文的阅读,希望读者们能够提高 Web 应用系统的安全性防范意识,提高对前端的技术认识,促进自身的职业发展。