Watching this video on json deserialization attacks and it shows this bit of json that can be used to trigger arbitrary code execution on any application that deserializes it.
Now in my applications, I never even use typed json. I always deserialize to dynamic objects or JObject
s. I didn't even know about the $type
property until another unrelated conversation this morning.
Is there a way in my json settings to tell it never to write nor read this property? It's not something I would ever want.
To ignore individual properties, use the [JsonIgnore] attribute. You can specify conditional exclusion by setting the [JsonIgnore] attribute's Condition property. The JsonIgnoreCondition enum provides the following options: Always - The property is always ignored.
This sample serializes an object to JSON with NullValueHandling set to Ignore so that properties with a default value aren't included in the JSON result.
Json does case-insensitive property name matching by default. The System. Text. Json default is case-sensitive, which gives better performance since it's doing an exact match.
In Deserialization, it does the opposite of Serialization which means it converts JSON string to custom . Net object. In the following code, it calls the static method DeserializeObject() of the JsonConvert class by passing JSON data. It returns a custom object (BlogSites) from JSON data.
"$type"
information is only written when TypeNameHandling
is modified to something other than TypeNameHandling.None
-- which is the default. If you never change the value, "$type"
information is never emitted.
Similarly "$type"
properties are ignored on deserialization when TypeNameHandling = TypeNameHandling.None
(which is, again, the default), as is stated in the docs:
// for security TypeNameHandling is required when deserializing
Stockholder newStockholder =
JsonConvert.DeserializeObject<Stockholder>(jsonTypeNameAuto, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
If nothing in your code (or in class libraries used by your code) ever modifies TypeNameHandling
to something other than TypeNameHandling.None
(either via settings or attributes such as JsonPropertyAttribute.TypeNameHandling
) then that code execution attack cannot work. (For more precise details on usages of Json.NET's serializer that are and are not vulnerable to this attack, see Alvaro Muñoz & Oleksandr Mirosh's blackhat paper.
Also note that, if you are parsing with JToken.Parse()
(or some similar static method like JObject.Parse()
) rather than deserializing with JsonSerializer.Deserialize<T>()
then the presence of "$type"
properties will simply result in such properties getting populated into the JToken
hierarchy, since JToken.Parse()
never invokes the serializer. If you nevertheless want to strip those"$type"
properties after parsing, you can use JsonExtensions.RemoveTypeMetadata(this JToken root)
from Deserialize string that was serialized with TypeNameHandling.All to do just that.
That being said, if a collection was serialized by another application using TypeNameHandling.Arrays
or TypeNameHandling.All
then there will be an extra level of nesting in the JSON. To strip it when deserializing, see IgnoreCollectionTypeConverter
from Strategies for migrating serialized Json.NET document between versions/formats or IgnoreArrayTypeConverter
from Make Json.NET ignore $type if it's incompatible.
Finally, if you are working with a 3rd party library that sets TypeNameHandling
in attributes, you can disable that with a custom contract resolver as shown in How to disable TypeNameHandling when specified in attributes by using JsonSerializerSettings in Json.NET?.
And if you're really concerned that somebody else in your team might enable TypeNameHandling
, you could create a custom ISerializationBinder
that throws an exception whenever an attempt is made to resolve a type or type name:
public class DisallowSerializationBindingBinder : ISerializationBinder
{
#region ISerializationBinder Members
public void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
throw new JsonSerializationException("Binding of subtypes has been disabled");
}
public Type BindToType(string assemblyName, string typeName)
{
throw new JsonSerializationException("Binding of subtypes has been disabled");
}
#endregion
}
Then set it in JsonSerializerSettings
as follows:
var settings = new JsonSerializerSettings
{
SerializationBinder = new DisallowSerializationBindingBinder(),
};
And modify the settings globally as shown in Set default global json serializer settings (for a console app), How to set custom JsonSerializerSettings for Json.NET in MVC 4 Web API? (for ASP.NET Web API) or JsonSerializerSettings and Asp.Net Core (for asp.net core).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With