FlawOpen

flawopen.com/Deserialización insegura/TypeNameHandling

Newtonsoft.Json TypeNameHandling: configuración segura para JSON no confiable?

CWE-502: Deserialization of Untrusted DataPágina de referencia
Respuesta breve

El JSON describe datos; tu código elige el tipo .NET. Con TypeNameHandling activado, $type puede influir en la resolución de tipos al deserializar. Usa None para entradas no confiables. Si necesitas polimorfismo, valida los tipos con un ISerializationBinder estricto o usa un mapeo cerrado de discriminadores declarado en el código.

VULNERABLE
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);
CORREGIDO
// 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+).

Por qué los desarrolladores activan TypeNameHandling

El motivo habitual son los datos polimórficos: una colección Shape puede tener que conservarse como Circle o Square. Json.NET lee y escribe nombres de tipo mediante $type. Con entradas no confiables, esos metadatos pueden influir en el tipo resuelto; el riesgo depende de los tipos permitidos y su comportamiento al deserializar. Una cadena peligrosa requiere un tipo alcanzable con efectos secundarios; el JSON por sí solo no basta.

El límite de confianza debe funcionar al revés: el código selecciona un subtipo de un conjunto cerrado de discriminadores validados. System.Text.Json permite polimorfismo opt-in mediante atributos como [JsonDerivedType]; no activa nombres CLR arbitrarios del JSON. Consulta la guía de BinaryFormatter para un límite relacionado.

¿Basta con un ISerializationBinder personalizado?

Un ISerializationBinder estricto es la defensa requerida por Json.NET cuando TypeNameHandling no es None para datos externos. Asocia solo unos pocos nombres exactos, propios de la aplicación, y rechaza el resto. Revisa los tipos permitidos, convertidores, constructores, setters y callbacks. El binder limita la resolución, pero no vuelve inocuos los tipos arbitrarios. Si controlas el protocolo, prefiere None y el despacho explícito.

Preguntas frecuentes

¿TypeNameHandling.Auto es seguro para JSON no confiable?

No por sí solo. Auto puede leer $type al deserializar. Usa TypeNameHandling.None o un ISerializationBinder estricto que solo permita tipos revisados.

¿System.Text.Json admite polimorfismo seguro?

Sí, de forma opt-in, con discriminador y tipos derivados declarados en código, como [JsonDerivedType] en .NET 7+. El código limita el conjunto, no nombres CLR arbitrarios del contenido.

¿Cómo audito una aplicación .NET?

Busca TypeNameHandling, SerializationBinder y JsonConvert.DeserializeObject en toda la solución. Incluye el inicio de ASP.NET y la configuración compartida; sigue los endpoints que pasan JSON externo y confirma un binder estricto en cada ruta distinta de None.

Referencias

Véase también Deserialización insegura: riesgos y defensa PHP unserialize() y datos no confiables Seguridad de pickle.load() en Python: riesgos de datos no confiables ¿Es seguro Ruby YAML.load? Versiones de Psych y safe_load .NET BinaryFormatter: riesgos y migración ObjectInputStream en Java: deserialización segura