我正在运营一个小型网站,用户可以在其中上传JSON中定义的自定义“对象”。最近,我了解了使用JSON自动类型反序列化的可能威胁:JSON problem。我认为我了解问题所在,但我必须要求确定。如果我仅使用给定的特定类型(此处为MyObject)反序列化传入的JSON,JsonConvert.DeserializeObject<MyObject>(json, settings);并且内部MyObject没有类型,MyObject并且该类型的任何成员的子类型都没有该类型,System.Object或者dynamic没有什么会变坏的,对吗?
MyObject
JsonConvert.DeserializeObject<MyObject>(json, settings);
System.Object
dynamic
TypeNameHandling的settings设置为TypeNameHandling.Auto(我们不要质疑这个决定,它可能可以与工作None,但我想了解的问题将其设置为Auto。)
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是一个非常复杂的对象(包含很多(派生的)子对象,但它们都不是或具有System.Object或动态字段(即使不是类似的东西List<Object>?例如,我可以想象,$type即使找不到相关字段,Json.NET 也会根据信息执行类似创建对象的操作MyObject。
obj
List<Object>
$type
TL / DR :在没有任何明显的object或dynamic成员,则 很可能 是安全的,但你不能 保证 是安全的。为了进一步降低风险,您应该遵循Newtonsoft文档中的建议:
object
当您的应用程序从外部源反序列化JSON时,应谨慎使用TypeNameHandling。反序列化除None以外的其他值时,应使用自定义SerializationBinder验证传入的类型。
完整答案
在Newtonsoft Json 和AlvaroMuñoz&Oleksandr Mirosh的blackhat 论文中, 如何配置Json.NET来创建易受攻击的Web API , TypeNameHandling警告中 描述的攻击都取决于使用Json.NET 的设置来诱骗接收者构造 攻击小工具 -一种实例,在构造,填充或放置时会对接收系统造成攻击。 TypeNameHandling
Json.NET做两件事可以帮助防止此类攻击。首先,它忽略未知属性。因此,只需向其值包含一个"$type"属性的JSON有效负载中添加一个额外的未知属性就不会造成任何危害。其次,在多态值的反序列化期间,在解析"$type"属性时,它将检查解析的类型是否与预期的类型兼容JsonSerializerInternalReader.ResolveTypeName():
"$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)); }
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,这很可能是真的。但不确定!
IDynamicMetaObjectProvider
即使数据模型中没有任何明显的非类型化成员,也可能构成攻击小工具的情况包括:
未类型化 集合的 反序列化。如果你是反序列化任何类型的非类型化的集合或字典,如ArrayList,List<object>,Dictionary<string, dynamic>或HashTable,那么你的系统很容易受到攻击包含在收集的物品的小工具。
ArrayList
List<object>
Dictionary<string, dynamic>
HashTable
对从继承的数十个集合中的任何一个进行反序列化CollectionBase。此类型早于.Net引入泛型之前,它表示“半类型”集合,其中,项的类型在添加时会在运行时进行验证。由于验证是在构造之后进行的,因此存在一个可能会构造攻击小工具的窗口。
CollectionBase
示例小提琴就显示了这一点。
对与攻击工具(不仅仅是)共享通用基本类型或接口的值进行反序列化object。 TempFileCollection实施ICollection和IDisposable。 ObjectDataProvider实施INotifyPropertyChanged和ISupportInitialize。如果您有任何声明为这些接口中任何一个的多态成员或值,则很容易受到攻击。
TempFileCollection
ICollection
IDisposable
ObjectDataProvider
INotifyPropertyChanged
ISupportInitialize
实现的类型的反序列化ISerializable。Json.NET 默认情况下支持此接口,并且某些外部库中看似无害的类型可能会在您不知情的情况下反序列化其流构造函数中的未类型化成员。
ISerializable
一个明显的例子是Sytem.Exception(或其任何子类型),它"Data"在其流构造函数中反序列化未类型字典,该流构造函数对应于未类型字典Exception.Data。如果要反序列化Exception(例如,很常见的包含在日志文件中),则以下JSON应该会造成攻击:
Sytem.Exception
"Data"
Exception.Data
Exception
{ "$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 } }, }
true`](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_Serialization_DefaultContractResolver_IgnoreSerializableInterface.htm)。当然,这可能会导致某些.Net类库类型的序列化问题。
[Serializable]如果设置,则反序列化标记为的类型可能会有类似的问题DefaultContractResolver.IgnoreSerializableAttribute = false。但是,默认值为true,因此,如果不更改此设置,则应该确定。
[Serializable]
DefaultContractResolver.IgnoreSerializableAttribute = false
true
使用您 认为 未序列化的成员反序列化类型-如果存在则将反序列化。例如考虑以下类型:
public MyType
{ public object tempData; public bool ShouldSerializeTempData() { return false; } }
借助Json.NET的条件序列化功能,该tempData成员将永远不会被序列化,因此您可能会觉得很清楚。但是,如果存在它将被 反序列化 !攻击者对您的代码进行反编译,并注意到这样的成员将能够为构建攻击小工具有效载荷MyType。
tempData
MyType
这就是我能够想到的。如您所见,验证在大型对象图中从未尝试反序列化与某些攻击小工具兼容的多态类型是很重要的。因此,我强烈建议对自定义项进行附加保护,以SerializationBinder确保不会反序列化任何意外类型。
SerializationBinder