Приведите примеры уязвимостей, связанных с небезопасной десериализацией (например, Java/ Python pickle), и опишите методы защиты и безопасные альтернативы
Примеры уязвимостей и пояснения - Java (ObjectInputStream, Java Serialization): - Проблема: десериализация байтового потока, содержащего объекты произвольных классов, позволяет собрать «gadget‑цепочки» (например, на базе Apache Commons‑Collections) и выполнить произвольный код при вызове readObject(). - Последствия: удалённое выполнение кода (RCE), эскалация привилегий, утечка/изменение данных. - Python (pickle, cPickle): - Проблема: pickle восстанавливает объекты, вызывая конструкторы/функции (через __reduce__/__reduce_ex__), поэтому данные могут содержать вызовы произвольных функций. - Последствия: RCE, выполнение shell‑команд, доступ к файловой системе. - PHP (unserialize): - Проблема: магические методы (__wakeup, __destruct, __toString) класса могут выполняться при десериализации; возможна object injection и использование gadget‑классов. - Последствия: RCE, изменение состояния приложения, обход контроля доступа. - .NET (BinaryFormatter, NetDataContractSerializer): - Аналогичные проблемы: восстановление объектов может приводить к выполнению произвольного кода через gadget‑цепочки. - YAML (PyYAML.load и подобные): - PyYAML.load может создавать произвольные Python‑объекты — риск аналогичен pickle. Методы защиты (конкретно и практично) 1. По возможности НЕ десериализовать данные из ненадёжных источников. 2. Использовать простые безопасные форматы: - JSON (строгая схема/валидация), Protocol Buffers, Avro, FlatBuffers — предпочтительнее, потому что не выполняют код при парсинге. 3. Аутентичность и целостность: - Подписывать/проверять сериализованные данные (например, HMAC или цифровая подпись). Десериализовать только после проверки подписи. 4. Фильтрация/whitelist типов: - Java: использовать ObjectInputFilter (Java 9+) или библиотечные фильтры, ограничивающие классы/размер/глубину графа; отключать Default Typing в Jackson; избегать polymorphic deserialization без whitelist. - Python: если pickle необходим, использовать пользовательский Unpickler с ограничением find_class (разрешать только конкретные модули/классы). 5. Использовать безопасные методы парсинга: - PyYAML: использовать yaml.safe_load вместо yaml.load. 6. Минимизировать «gadget‑поверхность»: - Удалять/не подключать библиотеки и классы, которые не нужны, чтобы снизить шанс наличия gadget‑классов. 7. Песочница/изоляция: - Десериализация выполняется в изолированном процессе/контейнере с ограниченными привилегиями; мониторинг и таймауты. 8. Ограничения по размерам и глубине: - Лимиты на входной размер, количество элементов и глубину объектов, чтобы предотвратить DoS и переполнения. 9. Валидация объектов после десериализации: - Проверять содержимое и типы полей, обязательные поля, границы и т. п., прежде чем использовать объект. 10. Обновление и аудит: - Регулярно обновлять библиотеки и проверять известные gadget‑цепочки/дополнительные патчи. Безопасные альтернативы (рекомендации) - Для структурированных данных: - JSON + JSON Schema (всегда валидировать). - Protocol Buffers / Avro / Thrift / FlatBuffers — схемо‑ориентированные бинарные форматы. - Для Java: - Jackson/Gson с явной привязкой к конкретным классам и без включения polymorphic typing; использовать ObjectInputFilter при необходимости. - Для Python: - json + pydantic/marshmallow/attrs/dataclasses + валидация типов вместо pickle. - Для передачи доверенных объектов между сервисами: - RPC/сериализация по контракту (gRPC, protobuf) и HTTPS + аутентификация/авторизация. Короткие примеры защитных приёмов - HMAC перед десериализацией: сервер проверяет HMAC(payload) с секретом, и только при совпадении — десериализует. - Whitelist‑Unpickler (Python): переопределить find_class и разрешить только конкретные модули/классы. - ObjectInputFilter (Java): задать шаблон разрешённых/запрещённых типов и лимиты по количеству/глубине. Итог — практическое правило - Если данные исходят из ненадёжного источника, не доверяйте бинарной/автоматической десериализации; используйте схемо‑управляемые форматы и проверяйте подпись/валидируйте структуру. Если десериализация неизбежна — комбинируйте whitelist, фильтры, изоляцию и проверку целостности.
- Java (ObjectInputStream, Java Serialization):
- Проблема: десериализация байтового потока, содержащего объекты произвольных классов, позволяет собрать «gadget‑цепочки» (например, на базе Apache Commons‑Collections) и выполнить произвольный код при вызове readObject().
- Последствия: удалённое выполнение кода (RCE), эскалация привилегий, утечка/изменение данных.
- Python (pickle, cPickle):
- Проблема: pickle восстанавливает объекты, вызывая конструкторы/функции (через __reduce__/__reduce_ex__), поэтому данные могут содержать вызовы произвольных функций.
- Последствия: RCE, выполнение shell‑команд, доступ к файловой системе.
- PHP (unserialize):
- Проблема: магические методы (__wakeup, __destruct, __toString) класса могут выполняться при десериализации; возможна object injection и использование gadget‑классов.
- Последствия: RCE, изменение состояния приложения, обход контроля доступа.
- .NET (BinaryFormatter, NetDataContractSerializer):
- Аналогичные проблемы: восстановление объектов может приводить к выполнению произвольного кода через gadget‑цепочки.
- YAML (PyYAML.load и подобные):
- PyYAML.load может создавать произвольные Python‑объекты — риск аналогичен pickle.
Методы защиты (конкретно и практично)
1. По возможности НЕ десериализовать данные из ненадёжных источников.
2. Использовать простые безопасные форматы:
- JSON (строгая схема/валидация), Protocol Buffers, Avro, FlatBuffers — предпочтительнее, потому что не выполняют код при парсинге.
3. Аутентичность и целостность:
- Подписывать/проверять сериализованные данные (например, HMAC или цифровая подпись). Десериализовать только после проверки подписи.
4. Фильтрация/whitelist типов:
- Java: использовать ObjectInputFilter (Java 9+) или библиотечные фильтры, ограничивающие классы/размер/глубину графа; отключать Default Typing в Jackson; избегать polymorphic deserialization без whitelist.
- Python: если pickle необходим, использовать пользовательский Unpickler с ограничением find_class (разрешать только конкретные модули/классы).
5. Использовать безопасные методы парсинга:
- PyYAML: использовать yaml.safe_load вместо yaml.load.
6. Минимизировать «gadget‑поверхность»:
- Удалять/не подключать библиотеки и классы, которые не нужны, чтобы снизить шанс наличия gadget‑классов.
7. Песочница/изоляция:
- Десериализация выполняется в изолированном процессе/контейнере с ограниченными привилегиями; мониторинг и таймауты.
8. Ограничения по размерам и глубине:
- Лимиты на входной размер, количество элементов и глубину объектов, чтобы предотвратить DoS и переполнения.
9. Валидация объектов после десериализации:
- Проверять содержимое и типы полей, обязательные поля, границы и т. п., прежде чем использовать объект.
10. Обновление и аудит:
- Регулярно обновлять библиотеки и проверять известные gadget‑цепочки/дополнительные патчи.
Безопасные альтернативы (рекомендации)
- Для структурированных данных:
- JSON + JSON Schema (всегда валидировать).
- Protocol Buffers / Avro / Thrift / FlatBuffers — схемо‑ориентированные бинарные форматы.
- Для Java:
- Jackson/Gson с явной привязкой к конкретным классам и без включения polymorphic typing; использовать ObjectInputFilter при необходимости.
- Для Python:
- json + pydantic/marshmallow/attrs/dataclasses + валидация типов вместо pickle.
- Для передачи доверенных объектов между сервисами:
- RPC/сериализация по контракту (gRPC, protobuf) и HTTPS + аутентификация/авторизация.
Короткие примеры защитных приёмов
- HMAC перед десериализацией: сервер проверяет HMAC(payload) с секретом, и только при совпадении — десериализует.
- Whitelist‑Unpickler (Python): переопределить find_class и разрешить только конкретные модули/классы.
- ObjectInputFilter (Java): задать шаблон разрешённых/запрещённых типов и лимиты по количеству/глубине.
Итог — практическое правило
- Если данные исходят из ненадёжного источника, не доверяйте бинарной/автоматической десериализации; используйте схемо‑управляемые форматы и проверяйте подпись/валидируйте структуру. Если десериализация неизбежна — комбинируйте whitelist, фильтры, изоляцию и проверку целостности.