我正在运营一个小型网站,用户可以在其中上传以 JSON 定义的自定义"对象"。最近,我了解了使用具有自动类型反序列化的 JSON 的可能威胁:JSON 问题。 我想我理解问题所在,但我必须问才能确定。如果我只反序列化具有给定特定类型(此处MyObject
)的传入 JSON,JsonConvert.DeserializeObject<MyObject>(json, settings);
并且MyObject
内部没有类型,并且MyObject
的任何成员的任何子类型都没有System.Object
或dynamic
类型,那么没有什么会变坏的,对吧?
TypeNameHandling
settings
设置为TypeNameHandling.Auto
(我们不要质疑这个决定,它可能适用于None
,但我想理解它设置为Auto
的问题。
编辑: 更多信息:我已经从前面提到的网站测试了JSON:
{
"obj": {
"$type": "System.IO.FileInfo, System.IO.FileSystem",
"fileName": "rce-test.txt",
"IsReadOnly": true
}
}
如果MyObject
具有System.Object
或dynamic
类型字段obj
我可以重现威胁。但我想知道的是:即使 MyObject 是一个非常复杂的对象,有很多(派生的)子对象,但我对准备不佳的 user-json 是安全的,但它们中没有一个是或具有System.Object
或动态字段(也不是像List<Object>
)? 例如,我可以想象 Json.NET 因为$type
信息而做一些类似创建对象的事情,即使找不到MyObject
中的 according 字段。
TL/DR:在没有任何明显的object
或dynamic
成员的情况下,您可能很安全,但不能保证安全。为了进一步降低风险,您应该遵循Newtonsoft文档中的建议:
当应用程序从外部源反序列化 JSON 时,应谨慎使用类型名称处理。使用非 None 的值反序列化时,应使用自定义序列化绑定程序验证传入类型。
完整答案
如何配置 Json.NET 以创建易受攻击的WebAPI,NewtonsoftJson中的TypeNameHandling Caution以及Alvaro Muñoz & Oleksandr Mirosh的黑帽论文中描述的攻击都依赖于使用 Json.NET 的TypeNameHandling
设置来诱骗接收者构建攻击小工具- 一种类型的实例,在构建,填充或处置时会对接收系统进行攻击。
Json.NET 做了两件事来帮助防止此类攻击。 首先,它忽略未知属性。 因此,只需将额外的未知属性添加到其值包含"$type"
属性的 JSON 有效负载应该不会造成伤害。 其次,在多态值的反序列化过程中,在解析"$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)); }
如果多态值的预期类型与任何攻击小工具类型不兼容,则攻击将失败。 如果你没有类型object
、dynamic
或IDynamicMetaObjectProvider
的可序列化成员,这很可能是正确的。 但不确定!
即使数据模型中没有任何明显的非类型化成员,也可能构建攻击小工具的情况包括:
-
非类型化集合的反序列化。 如果你正在反序列化任何类型的非类型集合或字典,如
ArrayList
、List<object>
、Dictionary<string, dynamic>
或HashTable
,那么你的系统很容易受到集合项目中包含的小工具的攻击。
从 CollectionBase
继承的数十个集合中的任何一个的反序列化。 此类型早于 .Net 中引入泛型,表示一个"半类型"集合,其中项的类型在添加时在运行时进行验证。 由于验证是在构造之后进行的,因此有一个窗口可以构建攻击小工具。示例小提琴显示了这一点。
与攻击小工具共享公共基本类型或接口的值的反序列化,而不仅仅是
object
.TempFileCollection
实现了ICollection
和IDisposable
。ObjectDataProvider
实现了INotifyPropertyChanged
和ISupportInitialize
。 如果您有任何声明为这些接口中的任何一个的多态成员或值,则容易受到攻击。实现
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 的条件序列化功能,
tempData
成员永远不会被序列化,因此您可能会认为您是明文的。 但如果存在,它将被反序列化! 反编译您的代码并注意到此类成员的攻击者将能够为MyType
创建攻击小工具有效负载。
而这正是我能够想到的。 如您所见,验证在大型对象图中,从未尝试反序列化与某些攻击小工具兼容的多态类型基本上是不平凡的。 因此,我强烈建议对自定义SerializationBinder
进行额外的保护,以确保不会反序列化任何意外类型。