通过将TypeNameHandling
设置为TypeNameHandling.Objects
,我正在做的事情已经在Json.net
中实现。这样,对象类型也将被序列化,并且反序列化的对象将具有完全原始的类型。
然而,使用TypeNameHandling
会暴露一些安全问题,并要求我们使用自定义SerializationBinder
来限制支持哪些类型,以避免可能的代码注入。这并不是我试图找到另一个解决方案的主要原因。事实上,我发现通过使用TypeNameHandling.Objects
,对象将被序列化为复杂的JSON,不仅包括对象数据本身和对象类型,还包括其他一些对我来说多余的属性。
我认为我们只需要多一个包含对象类型信息的属性(例如对象类型的程序集限定名称),所以我想创建一个自定义JsonConverter
,它将把任何对象序列化为一些JSON,如下所示:
{
"Item" : "normal JSON string of object",
"ItemType" : "assembly qualified name of object type"
}
这还不够吗?正如我之前所说,除了两个类似的属性(具有不同的名称)外,Json.net
库还包括一些其他属性(签名…),这些属性对我来说确实是多余的。
我不是在问如何实现我上面提到的自定义JsonConverter
。我只是想知道这个转换器(具有简化的JSON结构)是否可以,或者我应该使用Json.net
和TypeNameHandling
提供的标准解决方案(这涉及到更复杂的JSON结构)?我主要担心的是TypeNameHandling
设置为Objects
可能会出现性能问题,因为需要转换/序列化/传输更多数据。
标准解决方案的另一个问题是性能问题,实际上我只需要将自定义转换逻辑应用于精确类型object
的所有对象,而不是应用于所有其他强类型对象(TypeNameHandling
可能仍然不必要地应用这些逻辑?)
我对您提出的多态自定义JsonConverter
的设计有一些反应(我们称之为PolymorphicConverter<T>
,其中T
是基本类型):
-
关于安全,你写道,
。。。使用
TypeNameHandling
暴露了一些安全问题,并要求我们使用自定义SerializationBinder
来限制将支持哪些类型,以避免可能的代码注入。TypeNameHandling
可能出现的相同安全风险也会出现在PolymorphicConverter<T>
中。这里的风险是,攻击者欺骗一些多态反序列化代码来实例化攻击小工具。请参阅Newtonsoft Json中的TypeNameHandling警告和External Json漏洞,因为Json.Net TypeNameHandling-auto?举例说明。如果攻击者使用转换器支持的
"ItemType"
属性中指定的攻击小工具类型来伪造JSON,那么它最终可能会实例化攻击小工具并实施攻击。您可以通过仅对已知多态属性或数组项启用多态反序列化支持来减少攻击面,方法是将
PolymorphicConverter<T>
(或[JsonProperty(TypeNameHandling = TypeNameHandling.All)]
)仅应用于那些实际上是多态的属性——但如果这些属性的多态基类型恰好与攻击小工具兼容,你会很容易受到攻击。因此,无论使用什么机制,您仍然需要像自定义
SerializationBinder
这样的东西来过滤顽皮的类型,无论您如何在JSON中编码类型信息的细节如何。 -
JSON文件大小。Json.NET通过在对象的开头添加一个属性来编码类型信息:
"$type" : "assembly qualified name of object type"
您的计划是添加:
"ItemType" : "assembly qualified name of object type"
目前还不清楚为什么会有优势,除非你的类型名称在某种程度上更紧凑。
-
性能。你写的,
我主要担心的是
TypeNameHandling
设置为Objects
可能会出现性能问题,因为需要转换/序列化/传输更多数据。首先,为什么不直接测量并找出答案呢?看见https://ericlippert.com/2012/12/17/performance-rant/
其次,Newtonsoft有一个设置
MetadataPropertyHandling
,当设置为Default
时,假设多态属性"$type"
在每个对象中处于第一位,因此能够在不将整个JSON预加载到JToken
层次结构的情况下将它们流式传输。如果转换器无条件地预加载到
JToken
层次结构中以获取"ItemType"
属性的值,则其性能可能会更差。 -
关于将多态反序列化限制为仅需要的属性,您写道:
标准解决方案的另一个问题是性能问题,实际上我只需要将自定义转换逻辑应用于精确类型
object
的所有对象,而不是应用于所有其他强类型对象无论哪种方式,这都可以通过自定义
ContractResolver
实现。根据您选择的解决方案,覆盖DefaultContractResolver.CreateProperty
,当JsonProperty.PropertyType == typeof(object)
时,根据需要设置TypeNameHandling
或Converter
。