FlawOpen

flawopen.com/Небезопасная десериализация/Безопасность pickle в Python

Безопасен ли pickle.load() для недоверенных данных?

CWE-502: десериализация недоверенных данныхСправочная страница
Краткий ответ

Нет. Считайте pickle программой в посылке, а не пассивной записью: загрузка может запустить восстановление объекта до его проверки приложением. Для данных через границу доверия используйте формат, содержащий только данные.

ОПАСНО — недоверенные байты могут запустить код при загрузке
import pickle

# Never accept pickle bytes from a request, upload,
# shared cache, or other untrusted source.
obj = pickle.loads(untrusted_bytes)
БЕЗОПАСНЕЕ — разберите данные и проверьте схему
import json

def parse_profile(raw: bytes) -> dict[str, str]:
    if len(raw) > 65_536:
        raise ValueError("Payload too large")

    try:
        value = json.loads(raw)
    except (json.JSONDecodeError, UnicodeDecodeError):
        raise ValueError("Invalid JSON") from None

    if not isinstance(value, dict) or set(value) - {"display_name", "theme"}:
        raise ValueError("Invalid profile")

    name = value.get("display_name")
    theme = value.get("theme")
    if not isinstance(name, str) or len(name) > 80:
        raise ValueError("Invalid display name")
    if theme not in {"light", "dark"}:
        raise ValueError("Invalid theme")

    return {"display_name": name, "theme": theme}
Поток pickle:
Специфичная для Python последовательность байтов с описанием восстановления объектов, включая ссылки на globals и поведение восстановления.
Unpickling:
Интерпретация потока и восстановление графа объектов; при этом могут вызываться функции.
Граница доверия:
Место, где пользователь, сервис, загрузка или общее хранилище может контролировать или менять байты.
CWE-502:
Десериализация недоверенных данных; ущерб зависит от возможности подменить данные, которые загружает приложение.
Шаг 1

Недоверенные байты попадают в pickle

Загрузка, запрос, кэш или артефакт могут передать процессу данные pickle, контролируемые или изменённые атакующим.

Шаг 2

Unpickler разрешает globals

Интерпретатор обрабатывает инструкции восстановления; find_class() может импортировать и вернуть именованные globals, включая функции.

Шаг 3

Загрузка запускает поведение

Инструкции могут вызывать функции во время load() или loads(), до проверки результата приложением.

Шаг 4

Последствия зависят от прав процесса

Поведение выполняется с правами процесса Python. Сеть, секреты, файлы и изоляция определяют масштаб.

Почему загрузка pickle пересекает границу выполнения кода

Поток pickle может указывать globals и функции восстановления. При unpickling Unpickler.find_class() разрешает globals, включая функции; opcodes могут запускать восстановление. Опасна сама операция pickle.load() или pickle.loads() — отдельного последующего вызова execute нет. Получившийся код имеет права процесса. Это документированное свойство формата; не используйте pickle для обмена недоверенными данными.

Что исправляет JSON — и чего он не исправляет

Документация Python предупреждает: загрузка недоверенных или подменённых данных pickle может выполнить произвольный код, тогда как декодирование JSON само по себе не создаёт такой путь выполнения. JSON не проверяет ввод автоматически: ограничьте размер, требуйте ожидаемый верхний тип и поля, сверяйте значения со схемой и отдельно проверяйте авторизацию. Если старый процесс временно использует pickle, до загрузки аутентифицируйте точные байты защищённым ключом. Подпись подтверждает происхождение и целостность только при допущениях о ключе и не делает безопасными вредоносные данные доверенного подписанта. Перейдите на формат данных.

Частые вопросы

Делает ли ограниченный Unpickler безопасным pickle от атакующего?

Переопределение find_class() может ограничить globals, но трудно доказать безопасность загрузчика для всех протоколов и доступного поведения. Для байтов, контролируемых пользователем, предпочтителен формат данных.

Нужно ли проверять JSON?

Да. JSON избегает выполнения кода при декодировании, но приложение всё равно должно проверять типы, поля, размер, значения и права. Разделяйте разбор JSON и бизнес-правила.

Первичные источники

См. также Небезопасная десериализация: риски и защита | flawopen.com Безопасен ли Ruby YAML.load? Версии Psych и safe_load .NET BinaryFormatter: риски и переход Безопасность ObjectInputStream в Java: защита десериализации Newtonsoft.Json TypeNameHandling: безопасная настройка? PHP unserialize() и недоверенные данные