flawopen.com/Небезопасная десериализация/PHP unserialize()
Безопасен ли PHP unserialize() для недоверенных данных?
Не передавайте недоверенные данные в unserialize(), даже если задан allowed_classes. PHP может восстановить объекты и вызвать __unserialize() или __wakeup(); атакующий может использовать классы приложения или автозагрузчика. Для недоверенных данных используйте JSON. При ассоциативном декодировании JSON-объекты становятся массивами и не создают экземпляры классов приложения с поведением магических методов.
<?php // Cookie content is controlled by the client. $input = $_COOKIE['prefs'] ?? ''; $data = unserialize($input); // Restoring an object may invoke its // __unserialize() or __wakeup() method. // Later object destruction may invoke __destruct(). // The risk depends on available classes, // their serialized state, and reachable behavior.
<?php
$input = $_POST['prefs'] ?? null;
if (!is_string($input)) {
http_response_code(400);
exit;
}
try {
$data = json_decode(
$input,
true,
512,
JSON_THROW_ON_ERROR
);
} catch (JsonException $e) {
http_response_code(400);
exit;
}
if (!is_array($data)) {
http_response_code(400);
exit;
}
// Validate required keys and value types here.
Что требуется для цепочки внедрения объектов PHP
Внедрение объектов не означает автоматическое выполнение кода. Сериализованное значение должно назвать класс, который PHP может разрешить и который разрешён параметрами; восстановление или последующее использование также должно привести к поведению с влиянием на безопасность. При восстановлении PHP может вызвать __unserialize() или __wakeup(); __destruct() может выполниться при уничтожении объекта, а __toString() — только в строковом контексте.
Цепочка Property-Oriented Programming (POP) связывает поведение, уже присутствующее в приложении или загруженных зависимостях. Эксплуатируемость зависит от конкретных классов, сериализованных свойств, пути вызовов и условий выполнения. Цепочку гаджетов для цели нужно подтвердить; одного unserialize() недостаточно.
Почему фильтрация строки и allowed_classes не являются полной защитой
Блокировка маркера O:, фильтрация имён классов или ограничение длины не обеспечивают безопасную проверку PHP-сериализации. PHP прямо предупреждает не передавать недоверенный ввод в unserialize() независимо от allowed_classes. Запрещённые классы превращаются в __PHP_Incomplete_Class, но структура всё равно разбирается. Для доверенных старых данных проверяйте форму результата и ограничивайте глубину. Для состояния клиента используйте JSON.
Частые вопросы
Нет. Параметр запрещает обычное восстановление классов приложения; запрещённые объекты становятся __PHP_Incomplete_Class. PHP всё равно предостерегает от недоверенных данных для unserialize(), даже с этой опцией. Используйте её лишь как дополнительную защиту доверенных старых данных, проверяйте результат и ограничивайте max_depth. В руководстве PHP указано, что эта опция не влияет на перечисления.
Он может подтвердить целостность данных, созданных приложением, если ключ секретен и hash_equals() проверяет подпись до десериализации. Отклоняйте неверную подпись до разбора. HMAC не шифрует данные и не предотвращает повтор; при необходимости добавьте срок действия или nonce. Не подписывайте произвольные пользовательские данные, чтобы объявить их доверенными.
У них есть общий риск восстановления объектов из сериализованных данных, но форматы, хуки, разрешение классов и меры защиты различаются. Оценивайте каждый runtime и его классы отдельно; цепочка гаджетов для одной платформы не обязана работать в другой.
Источники
- Руководство PHP — unserialize()
- Руководство PHP — магические методы
- Руководство PHP — декодирование JSON
- Руководство PHP — __PHP_Incomplete_Class
- OWASP — внедрение объектов PHP
- CWE-502 — десериализация недоверенных данных
- Безопасен ли Python pickle для недоверенных данных?
- Безопасен ли Java ObjectInputStream для недоверенных данных?