Безопасность PHP: Почему передача объектов в функцию unserialize() из внешних источников данных является критической уязвимостью?
Функция unserialize() в PHP восстанавливает объект или структуру данных из сериализованной строки. На первый взгляд это удобный инструмент, однако передача в неё данных из внешних источников (GET/POST-параметры, cookies, заголовки HTTP, пользовательские файлы) является одной из наиболее критических уязвимостей в экосистеме PHP.
**Как работает уязвимость**
Когда PHP десериализует строку, он не просто восстанавливает данные — он воссоздаёт объекты и автоматически вызывает магические методы: __wakeup() и __destruct(). Злоумышленник может сформировать вредоносную сериализованную строку, которая при десериализации создаст объект нужного класса и запустит произвольный код через эти магические методы.
**PHP Object Injection**
Атака называется PHP Object Injection. Для её успеха необходимо:
1. Наличие вызова unserialize() с контролируемыми данными.
2. Присутствие в коде приложения (или подключённых библиотеках) классов с опасными магическими методами — так называемых «гаджетов» (gadgets).
Даже если собственный код разработчика безопасен, популярные фреймворки и библиотеки (Laravel, Symfony, Zend, Magento) содержат цепочки гаджетов, которые можно использовать для выполнения произвольного кода, удаления файлов, SQL-инъекций и других атак.
**Пример опасного сценария**
Предположим, класс FileLogger имеет метод __destruct(), который удаляет временный файл. Злоумышленник создаёт сериализованный объект FileLogger с произвольным путём к файлу — например, к конфигурационному файлу приложения. При десериализации __destruct() удалит указанный файл.
**Реальные последствия**
— Удалённое выполнение кода (RCE)
— Чтение и запись произвольных файлов
— SQL-инъекции через ORM
— Обход аутентификации
— Полная компрометация сервера
**Методы защиты**
1. **Никогда не передавать в unserialize() данные из внешних источников** — это главное правило.
2. Использовать безопасные форматы обмена данными: JSON (json_decode()), XML с валидацией.
3. Если десериализация необходима — применять параметр allowed_classes для ограничения допустимых классов: unserialize($data, [‘allowed_classes’ => false]).
4. Подписывать сериализованные данные криптографической подписью (HMAC) и проверять её до десериализации.
5. Регулярно обновлять зависимости и проверять их на известные цепочки гаджетов с помощью инструментов типа phpggc.
6. Использовать WAF и мониторинг аномальных запросов.
**Вывод**
Функция unserialize() сама по себе не является «плохой», но её использование с недоверенными данными открывает дверь для катастрофических атак. Современные приложения должны полностью исключить этот паттерн, заменив его безопасными альтернативами.
