由于 Json.Net TypeNameHandling auto,外部 json 易受攻击?

External json vulnerable because of Json.Net TypeNameHandling auto?(由于 Json.Net TypeNameHandling auto,外部 json 易受攻击?)

本文介绍了由于 Json.Net TypeNameHandling auto,外部 json 易受攻击?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在运营一个小型网站,用户可以在其中上传以 JSON 定义的自定义对象".最近我了解到使用带有自动类型反序列化的 JSON 可能存在的威胁:JSON 问题.我想我理解这些问题,但我必须要确定.如果我只用给定的特定类型(此处为 MyObject)JsonConvert.DeserializeObject(json, settings); 反序列化传入的 JSON,并且 MyObject 内没有类型 并且 MyObject 的任何成员的子类型都没有类型 System.Objectdynamic 没有什么会变坏,对吧?

settings

TypeNameHandling 设置为 TypeNameHandling.Auto(我们不要质疑这个决定,它可能适用于 None,但我想理解设置为 Auto 的问题.)

更多信息:我已经从前面提到的网站测试了 JSON:

<代码>{对象":{"$type": "System.IO.FileInfo, System.IO.FileSystem","fileName": "rce-test.txt",IsReadOnly":真}}

如果 MyObjectSystem.Objectdynamic 类型字段 obj 我可以重现威胁.但我想知道的是:即使 MyObject 是一个非常复杂的对象,它有很多(派生的)子对象,但没有一个是或有一个 System.Object 或动态字段(也不像 List<Object>)?例如.我可以想象 Json.NET 会因为 $type 信息而执行类似创建对象的操作,即使在 MyObject 中找不到相应的字段.

解决方案

TL/DR:在没有任何明显的objectdynamic 成员们,您可能是安全的,但您并不能保证是安全的.为了进一步降低您的风险,您应该遵循 Newtonsoft 文档中的建议:

<块引用>当您的应用程序反序列化 JSON 来自一个外部来源.当反序列化值为 other比无.

完整答案

如何配置 Json.NET 以创建易受攻击的 Web APINewtonsoft Json 中的 TypeNameHandling 谨慎 和 Alvaro Muñoz &Oleksandr Mirosh 的 blackhat 论文都依赖于使用 TypeNameHandling Json.NET 的设置 以欺骗接收者构造攻击小工具 - 一种类型的实例,在构造、填充或处置时会影响对接收系统的攻击.

Json.NET 做了两件事来帮助防止此类攻击.首先,它忽略了未知属性.因此,简单地向 JSON 有效负载添加一个额外的未知属性,其值包含 "$type" 属性应该没有害处.其次,在多态值的反序列化过程中,当解析 "$type" 属性时,它会检查解析的类型是否与 JsonSerializerInternalReader.ResolveTypeName():

<块引用>

 if (objectType != null#if HAVE_DYNAMIC&&objectType != typeof(IDynamicMetaObjectProvider)#万一&&!objectType.IsAssignableFrom(specifiedType)){throw JsonSerializationException.Create(reader, "JSON '{0}' 中指定的类型与'{1}' 不兼容.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));}

如果多态值的预期类型与任何攻击小工具类型不兼容,则攻击将失败.如果您没有 objectdynamicIDynamicMetaObjectProvider 类型的可序列化成员,这很可能是真的.但不确定!

即使您的数据模型中没有任何明显的无类型成员,也可能构建攻击小工具的情况包括:

  • 无类型集合的反序列化.如果您要反序列化任何类型的无类型集合或字典,例如 ArrayListListDictionaryHashTable,那么你的系统是容易受到包含在集合项目中的小工具的攻击.<​​/p>
  • 对继承自 CollectionBase.这种类型早于 .Net 中泛型的引入,它代表一个半类型"集合,其中项目的类型在添加时在运行时进行验证.由于验证发生在构造之后,因此存在一个可能构造攻击小工具的窗口.

    示例 fiddle 仅显示此内容.

  • 反序列化与攻击小工具共享公共基本类型或接口的值,而不仅仅是 object.TempFileCollection 实现 <代码>ICollection 和 IDisposable.ObjectDataProvider 实现INotifyPropertyChangedISupportInitialize.如果您有任何多态成员或值被声明为这些接口中的任何一个,那么您很容易受到攻击.

  • 实现 ISerializable.Json.NET默认支持这个接口,可以在您不知情的情况下,某些外部库中看似无害的类型正在反序列化其流构造函数中的无类型成员.

    一个明显的例子是 Sytem.Exception(或其任何子类型),它反序列化一个无类型字典 "Data" 在它的 流式构造函数 对应于无类型字典 Exception.Data.如果您要反序列化 Exception(例如包含在日志文件中,这很常见),则以下 JSON 应该会导致攻击:

    <代码>{"$type": "System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","ClassName": "System.Exception","Message": "淘气异常",数据": {"$type": "System.Collections.ListDictionaryInternal, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",数据": {"$type": "System.IO.FileInfo, System.IO.FileSystem","fileName": "rce-test.txt",IsReadOnly":真}},}

    通过设置 DefaultContractResolver.IgnoreSerializableInterface = true.当然,这可能会导致某些 .Net 类库类型的序列化出现问题.

  • 反序列化标记有 的类型如果您设置 DefaultContractResolver.IgnoreSerializableAttribute = false.不过默认是true,所以不改这个设置应该没问题.

  • 使用您认为成员的反序列化类型不会被序列化——但如果存在则将被反序列化.例如.考虑以下类型:

    public MyType{公共对象临时数据;public bool ShouldSerializeTempData() { return false;}}

    感谢 Json.NET 的 条件序列化功能,tempData 成员永远不会被序列化,所以你可能认为你很清楚.但如果存在,它将被反序列化!反编译您的代码并注意到此类成员的攻击者将能够为 MyType 制作攻击小工具有效负载.

  • 而这正是我能想到的.如您所见,验证在大型对象图中,永远不会尝试反序列化与某些攻击小工具兼容的多态类型,这基本上是不平凡的.因此,我强烈建议对自定义 SerializationBinder 确保没有意外的类型被反序列化.

    I'm operating a small website where users can upload custom "objects" defined in JSON. Recently I've learned about possible threats using JSON with automatic type deserialization: JSON problem. I think I understand the problematics but I have to ask to be sure. If I only deserialize the incoming JSON with a given specific type (here MyObject) JsonConvert.DeserializeObject<MyObject>(json, settings); and no type inside MyObject and no subtype of any member of MyObject has the type System.Object or dynamic there is nothing that can go bad, right?

    TypeNameHandling of settings is set to TypeNameHandling.Auto (let's not question this decision it probably could work with None, but I want to understand the question with it set to Auto.)

    Edit: More information: I have tested the JSON from the previously mentioned website:

    {
        "obj": {
            "$type": "System.IO.FileInfo, System.IO.FileSystem",
            "fileName": "rce-test.txt",
            "IsReadOnly": true
        }
    }
    

    If MyObject has a System.Object or dynamic typed field obj I can reproduce the threat. But what I want to know: I'm on the safe side with bad prepared user-json even if MyObject is a very complex Object with lots of (derived) sub objects but NONE of them is or has a System.Object or a dynamic field (also not something like List<Object>)? E.g. I could imagine that Json.NET does something like creating objects because of the $type information even if no according field in MyObject can be found.

    解决方案

    TL/DR: In the absence of any obvious object or dynamic members, you may well be safe, but you are not guaranteed to be safe. To further decrease your risk you should follow the recommendations from the Newtonsoft documentation:

    TypeNameHandling should be used with caution when your application deserializes JSON from an external source. Incoming types should be validated with a custom SerializationBinder when deserializing with a value other than None.

    Full Answer

    The attacks described in How to configure Json.NET to create a vulnerable web API, TypeNameHandling caution in Newtonsoft Json and Alvaro Muñoz & Oleksandr Mirosh's blackhat paper all depend on using the TypeNameHandling setting of Json.NET to trick the receiver into constructing an attack gadget - a instance of a type that when constructed, populated or disposed effects an attack on the receiving system.

    Json.NET does two things that help protect against such attacks. Firstly, it ignores unknown properties. Thus simply adding an additional, unknown property to a JSON payload whose value contains a "$type" property should do no harm. Secondly, during deserialization of a polymorphic value, when resolving the "$type" property, it checks to see whether the resolved type is compatible with the expected type in JsonSerializerInternalReader.ResolveTypeName():

        if (objectType != null
    #if HAVE_DYNAMIC
            && objectType != typeof(IDynamicMetaObjectProvider)
    #endif
            && !objectType.IsAssignableFrom(specifiedType))
        {
            throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
        }
    

    If the expected type of the polymorphic value is not compatible with any attack gadget type, the attack will fail. Provided you have no serializable members of type object, dynamic or IDynamicMetaObjectProvider, this is likely to be true. But not certain!

    Cases in which an attack gadget might get constructed even without any obvious untyped members in your data model include:

    • Deserialization of untyped collections. If you are deserializing any sort of untyped collection or dictionary such as ArrayList, List<object>, Dictionary<string, dynamic> or HashTable, then your system is vulnerable to attack gadgets contained in the collection's items.

    • Deserialization of any of the dozens of collections inheriting from CollectionBase. This type predates the introduction of generics in .Net and represents a "semi-typed" collection, in which the types of the items are validated in runtime as they are added. Since the validation occurs after construction, there is a window in which an attack gadget might get constructed.

      Sample fiddle showing just this.

    • Deserialization of values that share a common base type or interface with an attack gadget other than just object. TempFileCollection implements ICollection and IDisposable. ObjectDataProvider implements INotifyPropertyChanged and ISupportInitialize. If you have any polymorphic members or values that are declared to be any of these interfaces, you are vulnerable.

    • Deserialization of types that implement ISerializable. Json.NET supports this interface by default, and it is possible that a seemingly-harmless type in some external library is deserializing untyped members inside its streaming constructor without your knowledge.

      One obvious example is Sytem.Exception (or any of its subtypes) which deserializes an untyped dictionary "Data" inside its streaming constructor which corresponds to the untyped dictionary Exception.Data. If you are deserializing an Exception (contained in a log file for example, which is very common), the following JSON should effect an attack:

      {
        "$type": "System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
        "ClassName": "System.Exception",
        "Message": "naughty exception",
        "Data": {
          "$type": "System.Collections.ListDictionaryInternal, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
          "data": {
            "$type": "System.IO.FileInfo, System.IO.FileSystem",
            "fileName": "rce-test.txt",
            "IsReadOnly": true    
          }
        },
      }
      

      The attack can be mitigated without creation of a custom serialization binder by setting DefaultContractResolver.IgnoreSerializableInterface = true. Of course, this may cause problems with serialization of certain .Net class library types.

    • Deserializing types marked with [Serializable] can have a similar problem if you set DefaultContractResolver.IgnoreSerializableAttribute = false. However, the default is true, so you should be OK if you don't change this setting.

    • Deserializing types with members that you think are not serialized -- but will be deserialized if present. E.g. consider the following type:

      public MyType
      {
          public object tempData;
          public bool ShouldSerializeTempData() { return false; }
      }
      

      Thanks to Json.NET's conditional serialization functionality, the tempData member will never be serialized, so you might think you're in the clear. But it will be deserialized if present! An attacker who decompiles your code and notices such a member will be able to craft an attack gadget payload for MyType.

    And that's just what I was able to think of off the top of my head. As you can see, verifying that, in a large object graph, there is never an attempt to deserialize a polymorphic type that is compatible with some attack gadget is substantially nontrivial. Thus I'd strongly recommend the additional protection of a custom SerializationBinder that ensures that no unexpected types are deserialized.

    这篇关于由于 Json.Net TypeNameHandling auto,外部 json 易受攻击?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:由于 Json.Net TypeNameHandling auto,外部 json 易受攻击?

基础教程推荐