flawopen.com/Небезопасная десериализация/TypeNameHandling
Newtonsoft.Json TypeNameHandling: безопасная настройка для недоверенного JSON?
JSON описывает данные, а тип .NET выбирает код. При включённом TypeNameHandling значение $type может влиять на разрешение типа. Для недоверенного ввода используйте None. Если нужен полиморфизм, проверяйте типы строгим ISerializationBinder или закрытым сопоставлением дискриминаторов в коде.
var settings = new JsonSerializerSettings {
// Any non-None mode needs a strict binder
TypeNameHandling = TypeNameHandling.Auto,
// No binder: input $type can resolve CLR types
};
var value = JsonConvert.DeserializeObject<Base>(
untrustedJson, settings);
// Safest default for untrusted JSON var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None, }; // For polymorphism, dispatch over a closed set: var token = JObject.Parse(json); Base value = token["kind"]?.ToString() switch { "circle" => token.ToObject<Circle>(), "square" => token.ToObject<Square>(), _ => throw new JsonException("Unknown kind"), }; // System.Text.Json also supports opt-in derived // types through [JsonDerivedType] (.NET 7+).
Зачем разработчики включают TypeNameHandling
Частая причина — полиморфные данные: коллекцию Shape нужно сохранить как Circle или Square. Json.NET читает и записывает имена типов через $type. В недоверенных данных эти метаданные могут влиять на разрешаемый тип; риск зависит от разрешённых типов и их поведения. Опасная цепочка требует доступного типа с побочными эффектами; одного JSON недостаточно.
Граница доверия должна работать наоборот: код выбирает подтип из закрытого набора проверенных дискриминаторов. System.Text.Json поддерживает явный полиморфизм через атрибуты вроде [JsonDerivedType], но не активирует произвольные имена CLR из JSON. См. рекомендации по BinaryFormatter.
Достаточно ли собственного ISerializationBinder?
Строгий ISerializationBinder обязателен в Json.NET, если для внешних данных TypeNameHandling не равен None. Сопоставляйте лишь несколько точных имён типов приложения и отклоняйте остальные. Проверьте типы, конвертеры, конструкторы, сеттеры и callbacks. Binder ограничивает разрешение типов, но не делает произвольные типы безопасными. По возможности используйте None и явный выбор.
Частые вопросы
Сам по себе нет. Auto может читать $type при десериализации. Используйте TypeNameHandling.None или строгий ISerializationBinder, разрешающий только проверенные типы.
Да, явно включаемый: с дискриминатором и типами-наследниками из кода, например [JsonDerivedType] в .NET 7+. Набор ограничивает приложение, а не произвольные имена CLR из данных.
Ищите во всём решении TypeNameHandling, SerializationBinder и JsonConvert.DeserializeObject. Проверьте запуск ASP.NET и общие настройки, проследите внешние JSON-входы и подтвердите строгий binder для каждого пути, кроме None.
Источники
- Json.NET — Параметры сериализации: TypeNameHandling и SerializationBinder
- API Json.NET — ISerializationBinder
- Microsoft Learn — Полиморфизм в System.Text.Json
- CWE-502 — Десериализация недоверенных данных
- FlawOpen — Безопасен ли .NET BinaryFormatter?