【问题标题】:Is it possible to set Json.Net to ignore $type?是否可以将 Json.Net 设置为忽略 $type?
【发布时间】:2018-06-17 23:19:22
【问题描述】:

观看this video on json deserialization attacks,它显示了这段 json,可用于在任何反序列化它的应用程序上触发任意代码执行。

现在在我的应用程序中,我什至从不使用类型化的 json。我总是反序列化为动态对象或JObjects。我什至不知道$type 属性,直到今天早上另一个无关的谈话。

我的 json 设置中有没有办法告诉它永远不要写入或读取此属性?这不是我想要的。

【问题讨论】:

标签: c# json json.net


【解决方案1】:

很遗憾,TypeNameHandling.None 被忽略了。但你可以使用:

public static JsonSerializerSettings JsonSerializationSettings
        = new JsonSerializerSettings
{
    MetadataPropertyHandling = MetadataPropertyHandling.Ignore
};

【讨论】:

    【解决方案2】:

    "$type" 信息仅在将TypeNameHandling 修改为TypeNameHandling.None 以外的其他内容时写入——这是默认设置。如果您从不更改该值,则永远不会发出 "$type" 信息。

    类似地,"$type" 属性在反序列化时被忽略 TypeNameHandling = TypeNameHandling.None(这也是默认值),如 docs 中所述:

    // for security TypeNameHandling is required when deserializing
    Stockholder newStockholder =
      JsonConvert.DeserializeObject<Stockholder>(jsonTypeNameAuto, new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.Auto
    });
    

    如果您的代码(或您的代码使用的类库中)没有将TypeNameHandling 修改为TypeNameHandling.None 以外的其他内容(通过settingsJsonPropertyAttribute.TypeNameHandling 等属性),那么代码执行攻击不能工作。 (有关易受攻击和不易受攻击的 Json.NET 序列化程序的使用的更精确详细信息,请参阅Alvaro Muñoz & Oleksandr Mirosh's blackhat paper

    还要注意,如果您使用 JToken.Parse()(或类似的静态方法,如 JObject.Parse())进行解析,而不是使用 JsonSerializer.Deserialize&lt;T&gt;() 进行反序列化,那么 "$type" 属性的存在只会导致此类属性被填充到JToken 层次结构,因为 JToken.Parse() 从不调用序列化程序。如果您仍然想在解析后删除那些"$type" 属性,您可以使用 Deserialize string that was serialized with TypeNameHandling.All 中的JsonExtensions.RemoveTypeMetadata(this JToken root) 来做到这一点。

    话虽如此,如果 集合 被另一个应用程序使用 TypeNameHandling.ArraysTypeNameHandling.All 序列化,那么 JSON 中将会有额外的嵌套级别。要在反序列化时剥离它,请参阅 Strategies for migrating serialized Json.NET document between versions/formats 中的 IgnoreCollectionTypeConverterMake Json.NET ignore $type if it's incompatible 中的 IgnoreArrayTypeConverter

    最后,如果您正在使用在属性中设置 TypeNameHandling 的第 3 方库,您可以使用自定义合约解析器禁用它,如 How to disable TypeNameHandling when specified in attributes by using JsonSerializerSettings in Json.NET? 所示。

    如果您真的担心团队中的其他人可能会启用TypeNameHandling,您可以创建一个自定义ISerializationBinder,在尝试解析类型或类型名称时抛出异常:

    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
    }
    

    然后在JsonSerializerSettings中设置如下:

    var settings = new JsonSerializerSettings
    {
        SerializationBinder = new DisallowSerializationBindingBinder(),
    };
    

    并修改全局设置,如 Set default global json serializer settings(对于控制台应用程序)、How to set custom JsonSerializerSettings for Json.NET in MVC 4 Web API?(对于 ASP.NET Web API)或 中所示JsonSerializerSettings and Asp.Net Core(用于 asp.net 核心)。

    【讨论】:

    • 我希望将TypeNameHandling 设置为All/Objects,但我仍然希望能够跳过特定的属性/类型,以便不会为它们生成$type .
    • @Shimmy - 对于特定属性,您可以从 this answer 开始,对于特定类型,您可以从 this answerthis one 开始,在适当的位置使用 TypeNameHandling.None。如果您需要特定的东西,您可能想问另一个问题。
    • 感谢您的快速回复!我希望它会起作用。
    • 我想知道是否可以避免装饰我的 Json。我目前正在反序列化一个非常复杂的对象,我必须用诸如 $type: "System.Collections.Generic.List`1[[ClassName, Namespace]], mscorlib" 之类的东西来污染我的 Json。我正在设置 TypeNameHandling.All。不做这两件事会阻止反序列化正常工作。欢迎任何提示或指示。
    • @progLearner - 如果您不想要 $type 属性,您可以创建自定义转换器来测试传入的 JSON 以查看它匹配的子类型。请参阅:Deserializing polymorphic json classes without type information using json.net
    猜你喜欢
    • 2015-04-19
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    • 2012-06-18
    • 1970-01-01
    • 2022-01-13
    • 2016-08-20
    相关资源
    最近更新 更多