Search code examples
c#serializationjson.net

TypeNameHandling caution in Newtonsoft Json


On this link, in remarks section it's mentioned that:

TypeNameHandling should be used with caution when your application deserializes JSON from an external source. Incoming types should be validated with a custom SerializationBinder when deserializing with a value other than TypeNameHandling.None.

In what cases JSON from external source would be harmful if serialized/deserialized with TypeNameHandling.All? A working example would be appreciated.


Solution

  • When deserialize with TypeNameHandling.All and without a SerializationBinder checks json.net will try to create a instace of the type that comes as metadata in the JSON.

    public class Car
    {
        public string Maker { get; set; }
        public string Model { get; set; }
    }
    
    {
       "$type": "Car",
       "Maker": "Ford",
       "Model": "Explorer"
    } //create a Car and set property values
    

    But an attacker could send you dangerous types that exist in your code or in the framework.

    i.e. from here System.CodeDom.Compiler.TempFileCollection is a serializable class whose purpose is to maintain a list of temporary files which resulted from a compilation process and delete them when they are no longer needed. To ensure that the files are deleted the class implements a finalizer that will be called when the object is being cleaned up by the Garbage Collector. An attacker would be able to construct a serialized version of this class which pointed its internal file collection to any file on a victims system. This will be deleted at some point after deserialization without any interaction from the deserializing application.

        [Serializable]
        public class TempFileCollection
        {
           private Hashtable files;
           // Other stuff...
    
           ~TempFileCollection()
           {
             if (KeepFiles) {return}
             foreach (string file in files.Keys)
             {
                File.Delete(file);
             }
           }
        }
    
       {
           "$type": "System.CodeDom.Compiler.TempFileCollection",
           "BasePath": "%SYSTEMDRIVE",
           "KeepFiles": "False",
           "TempDir": "%SYSTEMROOT%"
        } // or something like this, I just guessing but you got the idea