ТестированиеТестирование безопасностиИнженер по безопасности приложений

При аудите сервиса, принимающего сериализованные объекты от клиента, как доказать, что десериализация не пр...

При аудите сервиса, принимающего сериализованные объекты от клиента, как доказать, что десериализация не приводит к выполнению логики на стороне сервера?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

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

Исторический контекст

Механизмы сериализации появились для сохранения объектов, передачи структур между процессами и реализации удалённых вызовов. Их исходная модель предполагала, что отправитель и получатель доверяют друг другу, поэтому восстановление объекта могло автоматически вызывать конструкторы, обработчики восстановления или другую служебную логику.

Когда такие форматы стали использоваться на границе приложения, клиент получил возможность влиять не только на значения полей, но иногда и на типы восстанавливаемых объектов. Это породило класс уязвимостей небезопасной десериализации.

Постановка проблемы

Если сервер принимает недоверенный сериализованный объект и восстанавливает его без строгих ограничений, атакующий может попытаться выбрать неожиданный тип, изменить вложенную структуру или задействовать цепочку объектов с опасными побочными эффектами. Последствия варьируются от обхода проверок и подделки состояния до чтения файлов, отправки сетевых запросов и выполнения команд — в зависимости от формата, библиотеки и доступных классов.

Одной проверки подписи или шифрования недостаточно как универсальной защиты. Подписанные данные защищают целостность только при условии, что злоумышленник не может получить корректную подпись, но сама десериализация всё равно может быть опасной для любого подписанного объекта, сформированного доверенным, однако неподходящим источником.

Подробное решение

Сначала нужно определить, что именно принимает endpoint: простой набор полей, полиморфную структуру с метаданными типов или полноценное представление внутренних объектов. Затем проверяют, может ли клиент управлять именем типа, классом, ссылками между объектами и специальными полями восстановления.

Безопасная проверка включает следующие шаги:

  • изучить документацию и конфигурацию десериализатора: разрешены ли полиморфизм, автоматическое определение типов и произвольные классы;
  • отправить штатный объект с безопасно изменёнными значениями и убедиться, что сервер обрабатывает только ожидаемую модель;
  • проверить реакцию на неизвестный тип, неожиданные вложенные объекты, дублирующиеся поля и чрезмерную глубину структуры;
  • в тестовой среде использовать безвредный диагностический класс или маркер, позволяющий обнаружить вызов обработчика восстановления без выполнения команды;
  • сопоставить результат с журналами, сетевыми событиями и трассировкой, чтобы отличить обычную ошибку разбора от выполнения серверной логики.

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

Тест не должен без необходимости использовать полезные нагрузки для выполнения команд или чтения секретов. В рабочей среде достаточно доказать возможность управления типом или вызова контролируемого побочного эффекта; эксплуатационные действия выполняют только с явным разрешением и в изолированной среде.

Ситуация из практики

Сервис обмена заданиями принимал сериализованные объекты от внутренних клиентов. Рассматривались три варианта: оставить формат без изменений, добавить только проверку подписи или перейти на строго описанную структуру данных.

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

Выбрали переход на ограниченную схему данных с явным преобразованием в серверную модель. Дополнительно запретили неизвестные поля, ограничили размер и глубину входа, а тесты проверяли отказ при попытке передать метаданные типов. В результате endpoint сохранил нужную функциональность, но клиент больше не мог выбирать внутренний класс или запускать его служебную логику.

Что кандидаты часто упускают

  1. Достаточно ли запретить выполнение команд, чтобы устранить риск небезопасной десериализации?

Нет. Опасные последствия могут возникать без запуска команд: например, через обращение к внутреннему адресу, чтение локальных ресурсов, изменение состояния объекта, обход авторизации или исчерпание памяти. Запрет конкретной операции уменьшает ущерб, но не заменяет отказ от произвольной десериализации.

  1. Почему проверка типа после десериализации может быть недостаточной?

Проверка выполняется слишком поздно, если библиотека уже создала объект и вызвала его специальные обработчики восстановления. Опасное поведение может произойти до того, как приложение проверит получившийся тип. Ограничения должны применяться во время разбора входа или до создания объекта, например через allowlist типов и безопасный режим десериализатора.

  1. Как отличить небезопасную десериализацию от обычного разбора пользовательского JSON?

Сам по себе JSON не гарантирует безопасность: риск определяется тем, что делает приложение после разбора. Если JSON преобразуется в заранее определённую структуру примитивных значений с проверкой схемы, это обычно безопаснее. Если же из него восстанавливаются произвольные классы, учитываются метаданные типов или автоматически вызываются обработчики объектов, появляется риск, характерный для небезопасной десериализации.