外部json因为Json.Net TypeNameHandling auto而易受攻击?

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

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

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

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

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

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

当您的应用程序从外部源反序列化JSON时,应谨慎使用TypeNameHandling 。 使用非None以外的值进行反序列化时,应使用自定义SerializationBindervalidation传入类型。

完整答案

如何配置Json.NET以创建易受攻击的Web API中的攻击 ,Newtonsoft Json和AlvaroMuñoz&Oleksandr Mirosh的黑帽纸中的 TypeNameHandling注意事项都依赖于使用Json.NET的TypeNameHandling设置来欺骗接收者构建攻击小工具 – 构造,填充或处置的类型实例会对接收系统产生攻击。

Json.NET做了两件有助于防范此类攻击的事情。 首先,它忽略了未知的属性。 因此,简单地向JSON有效负载添加一个额外的未知属性,其值包含"$type"属性应该没有坏处。 其次,在对多态值进行反序列化时,在解析"$type"属性时,它会检查已解析的类型是否与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)); } 

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

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

  • 无类型集合的反序列化。 如果要反序列化任何类型的无类型集合或字典,例如ArrayListListDictionaryHashTable ,那么您的系统很容易受到集合项中包含的攻击小工具的攻击。

  • CollectionBaseinheritance的数十个集合中的任何一个的反序列化。 这种类型早于在.Net中引入generics,并且表示“半类型”集合,其中项目的类型在添加时在运行时validation。 由于validation发生在构造之后,因此有一个窗口可以构建攻击小工具。

    示例小提琴就是这样。

  • 对除了object之外的攻击小工具共享公共基本类型或接口的值进行反序列化。 TempFileCollection实现ICollectionIDisposableObjectDataProvider实现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": "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 } }, } 

    通过设置DefaultContractResolver.IgnoreSerializableInterface = true可以在不创建自定义序列化绑定程序的情况下缓解攻击。 当然,这可能会导致某些.Net类库类型的序列化问题。

  • 如果设置DefaultContractResolver.IgnoreSerializableAttribute = false则使用[Serializable]标记的反序列化类型可能会出现类似的问题。 但是,默认值为true ,因此如果不更改此设置,则应该没问题。

  • 使用您认为未序列化的成员反序列化类型 – 但如果存在则将反序列化。 例如,考虑以下类型:

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

    由于Json.NET的条件序列化function, tempData成员永远不会被序列化,所以你可能会认为你是明确的。 但如果存在,它将被反序列化 ! 反编译您的代码并通知此类成员的攻击者将能够为MyType制作攻击小工具负载。

这就是我能想到的最重要的事情。 正如您所看到的,validation在大型对象图中,从来没有尝试反序列化与某些攻击小工具兼容的多态类型,这实际上是非常重要的。 因此,我强烈建议对自定义SerializationBinder进行额外保护,以确保不会反SerializationBinder任何意外类型。