自定义JSON转换器可帮助反序列化为原始类型的对象

时间:2019-02-12 05:25:58

标签: c# json.net

通过将Json.net设置为TypeNameHandlingTypeNameHandling.Objects中实现了我正在做的事情。这样,对象类型也将被序列化,反序列化的对象将具有确切的原始类型。

但是,使用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申请?)

1 个答案:

答案 0 :(得分:1)

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

  1. 关于安全性,您写道,

      

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

    TypeNameHandling也将产生与PolymorphicConverter<T>相同的安全风险。

    这里的风险是,攻击者欺骗了一些多态反序列化代码以实例化攻击小工具。有关示例和讨论,请参见TypeNameHandling caution in Newtonsoft JsonExternal json vulnerable because of Json.Net TypeNameHandling auto?。如果攻击者使用转换器支持的"ItemType"属性中指定的攻击工具类型来制作JSON,则最终可能会实例化攻击工具并实施攻击。

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

    因此,无论使用哪种机制,无论如何在JSON中对类型信息进行编码的细节,您仍将需要诸如定制SerializationBinder之类的东西来过滤掉顽皮的类型。

  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的所有对象,而不是应用于所有其他强类型对象

    无论哪种方式,custom ContractResolver都可以实现。覆盖DefaultContractResolver.CreateProperty,并在JsonProperty.PropertyType == typeof(object)时根据需要设置TypeNameHandlingConverter,具体取决于您选择的解决方案。