FlawOpen

flawopen.com/Désérialisation non sécurisée/TypeNameHandling

Newtonsoft.Json TypeNameHandling : configuration sûre pour le JSON non fiable ?

CWE-502: Deserialization of Untrusted DataPage de référence
Réponse courte

Le JSON décrit les données ; votre code choisit le type .NET. Avec TypeNameHandling, $type peut influencer la résolution de type pendant la désérialisation. Gardez None pour les entrées non fiables. Si le polymorphisme est nécessaire, validez les types avec un ISerializationBinder strict ou utilisez une correspondance fermée de discriminateurs déclarée dans le code.

VULNÉRABLE
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);
CORRIGÉ
// 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+).

Pourquoi les développeurs activent TypeNameHandling

Les données polymorphes en sont la raison habituelle : une collection Shape peut devoir être restaurée comme Circle ou Square. Json.NET lit et écrit les noms de type via $type. Avec une entrée non fiable, ces métadonnées peuvent influencer le type résolu ; le risque dépend des types autorisés et de leur comportement à la désérialisation. Une chaîne dangereuse exige un type accessible ayant des effets de bord ; le JSON seul ne suffit pas.

La frontière de confiance doit fonctionner à l’inverse : le code choisit un sous-type parmi un ensemble fermé de discriminateurs validés. System.Text.Json propose le polymorphisme opt-in par des attributs comme [JsonDerivedType] ; il n’active pas de noms CLR arbitraires du JSON. Consultez les conseils sur BinaryFormatter pour une frontière connexe.

Un ISerializationBinder personnalisé suffit-il ?

Un ISerializationBinder strict est la défense requise par Json.NET lorsque TypeNameHandling diffère de None pour les données externes. Associez seulement quelques noms exacts appartenant à l’application et rejetez les autres. Examinez les types, convertisseurs, constructeurs, setters et callbacks autorisés. Le binder limite la résolution sans rendre les types arbitraires inoffensifs. Si vous contrôlez le protocole, préférez None et une sélection explicite.

FAQ

TypeNameHandling.Auto est-il sûr pour du JSON non fiable ?

Pas à lui seul. Auto peut lire $type à la désérialisation. Utilisez TypeNameHandling.None ou un ISerializationBinder strict qui n’autorise que des types examinés.

System.Text.Json prend-il en charge un polymorphisme sûr ?

Oui, en opt-in, avec un discriminateur et des types dérivés déclarés dans le code, comme [JsonDerivedType] sous .NET 7+. Le code borne l’ensemble plutôt que des noms CLR arbitraires dans la charge utile.

Comment auditer une application .NET ?

Recherchez TypeNameHandling, SerializationBinder et JsonConvert.DeserializeObject dans toute la solution. Incluez le démarrage ASP.NET et les paramètres partagés ; suivez les points d’entrée qui transmettent du JSON externe et vérifiez un binder strict sur chaque chemin différent de None.

Références

À voir aussi Désérialisation non sécurisée : risques et défense PHP unserialize() et les données non fiables Python pickle.load() : risques des données non fiables Ruby YAML.load est-il sûr ? Versions de Psych et safe_load .NET BinaryFormatter : risques et migration Sécurité d’ObjectInputStream en Java : désérialisation sûre