自定义JSON转换器,帮助反序列化回完全原始类型的对象



通过将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.netTypeNameHandling提供的标准解决方案(这涉及到更复杂的JSON结构)?我主要担心的是TypeNameHandling设置为Objects可能会出现性能问题,因为需要转换/序列化/传输更多数据。

标准解决方案的另一个问题是性能问题,实际上我只需要将自定义转换逻辑应用于精确类型object的所有对象,而不是应用于所有其他强类型对象(TypeNameHandling可能仍然不必要地应用这些逻辑?)

我对您提出的多态自定义JsonConverter的设计有一些反应(我们称之为PolymorphicConverter<T>,其中T是基本类型):

  1. 关于安全,你写道,

    。。。使用TypeNameHandling暴露了一些安全问题,并要求我们使用自定义SerializationBinder来限制将支持哪些类型,以避免可能的代码注入。

    TypeNameHandling可能出现的相同安全风险也会出现在PolymorphicConverter<T>中。

    这里的风险是,攻击者欺骗一些多态反序列化代码来实例化攻击小工具。请参阅Newtonsoft Json中的TypeNameHandling警告和External Json漏洞,因为Json.Net TypeNameHandling-auto?举例说明。如果攻击者使用转换器支持的"ItemType"属性中指定的攻击小工具类型来伪造JSON,那么它最终可能会实例化攻击小工具并实施攻击。

    您可以通过仅对已知多态属性或数组项启用多态反序列化支持来减少攻击面,方法是将PolymorphicConverter<T>(或[JsonProperty(TypeNameHandling = TypeNameHandling.All)])仅应用于那些实际上是多态的属性——但如果这些属性的多态基类型恰好与攻击小工具兼容,你会很容易受到攻击。

    因此,无论使用什么机制,您仍然需要像自定义SerializationBinder这样的东西来过滤顽皮的类型,无论您如何在JSON中编码类型信息的细节如何。

  2. JSON文件大小。Json.NET通过在对象的开头添加一个属性来编码类型信息:

    "$type" : "assembly qualified name of object type"
    

    您的计划是添加:

    "ItemType" : "assembly qualified name of object type"
    

    目前还不清楚为什么会有优势,除非你的类型名称在某种程度上更紧凑。

  3. 性能。你写的,

    我主要担心的是TypeNameHandling设置为Objects可能会出现性能问题,因为需要转换/序列化/传输更多数据。

    首先,为什么不直接测量并找出答案呢?看见https://ericlippert.com/2012/12/17/performance-rant/

    其次,Newtonsoft有一个设置MetadataPropertyHandling,当设置为Default时,假设多态属性"$type"在每个对象中处于第一位,因此能够在不将整个JSON预加载到JToken层次结构的情况下将它们流式传输。

    如果转换器无条件地预加载到JToken层次结构中以获取"ItemType"属性的值,则其性能可能会更差。

  4. 关于将多态反序列化限制为仅需要的属性,您写道:

    标准解决方案的另一个问题是性能问题,实际上我只需要将自定义转换逻辑应用于精确类型object的所有对象,而不是应用于所有其他强类型对象

    无论哪种方式,这都可以通过自定义ContractResolver实现。根据您选择的解决方案,覆盖DefaultContractResolver.CreateProperty,当JsonProperty.PropertyType == typeof(object)时,根据需要设置TypeNameHandlingConverter

相关内容

  • 没有找到相关文章

最新更新