FlawOpen

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

Безопасен ли BinaryFormatter в .NET?

CWE-502: Deserialization of Untrusted DataСправочная страница
Короткий ответ: безопасной настройки нет

Microsoft считает BinaryFormatter небезопасным и указывает, что сделать его безопасным нельзя. Она рекомендует прекратить его использование, даже если приложение считает данные доверенными. В .NET 9 типы API остаются, но встроенная реализация всегда вызывает PlatformNotSupportedException; старые среды выполнения и неподдерживаемый пакет совместимости сохраняют исходный риск.

ОПАСНО
// Не десериализуйте данные через границу доверия.
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public static class LegacyReader
{
    public static object Deserialize(Stream input) =>
        new BinaryFormatter().Deserialize(input);
}

// Удалите и эти неограниченные полиморфные сериализаторы:
SoapFormatter
NetDataContractSerializer
LosFormatter
ObjectStateFormatter  // используется внутри ASP.NET ViewState

// SerializationBinder не делает эти форматы безопасными.
МИГРАЦИЯ
// Форму данных задаёт код приложения.
// Nullable reference types make the DTO contract explicit.
#nullable enable
using System;
using System.IO;
using System.Text.Json;

public sealed record MyDto(int Id, string Name);

public static class DtoReader
{
    public static MyDto Parse(ReadOnlySpan<byte> json)
    {
        // Ограничьте размер входа и проверьте правила приложения.
        if (json.Length > 65_536)
            throw new InvalidDataException();

        MyDto? value = JsonSerializer.Deserialize<MyDto>(json);
        if (value is null || value.Id <= 0 ||
            string.IsNullOrWhiteSpace(value.Name) ||
            value.Name.Length > 100)
            throw new InvalidDataException();

        return value;
    }
}

// Для старых NRBF-файлов изучите записи через NrbfDecoder
// и перенесите разрешённые значения в DTO.
// Не создавайте произвольные типы runtime.

Почему BinaryFormatter опасен

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

Риск не ограничивается общедоступными HTTP-точками. Файлы, кэш, очереди, записи базы данных, сообщения настольных клиентов и синхронизируемое облако состояние позднее могут контролироваться атакующим. Проследите путь байтов в системе: пометки «мы это записали» или «это внутреннее» не являются постоянной гарантией доверия.

Почему SerializationBinder не решает проблему

Собственный SerializationBinder может ограничить типы, которые форматтер пытается разрешить, но Microsoft прямо заявляет: binder и другие настройки не устраняют отказ в обслуживании и могут быть недостаточны против других атак. Binder не заменяет миграцию; не принимайте недоверенные данные, пока удаляете BinaryFormatter.

Найдите старые вызовы и связанные пути

Ищите в исходниках, зависимостях проектов и настройках runtime: BinaryFormatter, IFormatter, SoapFormatter, NetDataContractSerializer, LosFormatter и ObjectStateFormatter. Проверьте поставщики состояния сеанса, адаптеры кэша, обработчики очередей, импорт/экспорт файлов и старые приложения ASP.NET Web Forms. ViewState обычно защищён кодом аутентификации сообщения (MAC); сохраняйте эту защиту и защищайте machine key. MAC не делает универсальную десериализацию BinaryFormatter безопасной.

Планируйте миграцию по формату данных и версии runtime

Для новых данных выберите явный контракт, например System.Text.Json, DataContractSerializer, MessagePack или protobuf-net, с учётом формата и совместимости; прямой замены нет. Для сохранения старых NRBF-файлов NrbfDecoder из .NET 9 может декодировать записи без создания закодированных типов приложения. Проверьте структуру и переносите только ожидаемые значения в DTO. Отдельно изучите рекомендации по миграции ресурсов, буфера обмена и drag-and-drop WinForms/WPF.

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

Мы десериализуем только данные, которые сами записали. Это безопасно?

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

Что изменится при переходе на .NET 9?

В .NET 9 типы API остаются, но встроенная реализация всегда вызывает PlatformNotSupportedException, независимо от прежнего флага совместимости. Проверьте вызовы и мигрируйте до обновления. Неподдерживаемый пакет совместимости возвращает уязвимую реализацию, но не исправляет безопасность.

Безопасен ли Json.NET как замена?

По умолчанию Json.NET задаёт TypeNameHandling как None, поэтому метаданные payload не выбирают произвольные CLR-типы. Не включайте другие значения для недоверенных данных. Если нужна полиморфность, используйте строгий allowlist под контролем приложения и следуйте документации библиотеки. См. Безопасен ли TypeNameHandling?

Источники и ссылки

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