Короткий ответ
pickle и небезопасный yaml.load могут при десериализации выполнять произвольный код, встроенный в сериализованные данные, поэтому для данных из недоверенного источника нужно использовать безопасные форматы: json.loads для универсальных данных и yaml.safe_load вместо yaml.load для YAML.
Как это работает подробнее
Формат pickle может описывать вызов практически любого объекта Python, включая классы с произвольным кодом в __reduce__, который выполнится в процессе десериализации; аналогично небезопасный YAML-загрузчик по умолчанию в PyYAML поддерживает теги для создания произвольных Python-объектов.
Пример кода
example.py
import json
import yaml
def parse_json(payload: bytes) -> dict:
return json.loads(payload)
def parse_yaml(payload: str) -> dict:
return yaml.safe_load(payload)Что использовать на практике
- Практика. pickle допустимо использовать только для данных, которые приложение само сериализовало и хранит в доверенном месте (внутренний кэш одного и того же сервиса), но не для данных, пришедших по сети от клиента или из очереди, доступной внешним системам; для межсервисного обмена предпочтительны json, protobuf или msgpack.
Подводные камни
- Риск. Используют pickle для сериализации сессий или сообщений очереди, доступных для записи клиентам или сторонними системами; вызывают yaml.load(data) без Loader=yaml.SafeLoader; не ограничивают размер входных данных перед десериализацией, что дополнительно создаёт риск DoS.