C# 外部json易受攻击,因为json.Net TypeNameHandling自动?

C# 外部json易受攻击,因为json.Net TypeNameHandling自动?,c#,json.net,C#,Json.net,我正在运营一个小网站,用户可以上传JSON定义的自定义“对象”。最近,我了解到使用JSON进行自动类型反序列化可能带来的威胁:。我想我理解这些问题,但我必须问清楚。如果我只使用给定的特定类型反序列化传入的JSON(这里是MyObject)JsonConvert.DeserializeObject(JSON,设置)

我正在运营一个小网站,用户可以上传JSON定义的自定义“对象”。最近,我了解到使用JSON进行自动类型反序列化可能带来的威胁:。我想我理解这些问题,但我必须问清楚。如果我只使用给定的特定类型反序列化传入的JSON(这里是
MyObject
JsonConvert.DeserializeObject(JSON,设置)MyObject
中没有类型,并且
MyObject
的任何成员的子类型都没有类型
系统。Object
dynamic
没有什么会坏的,对吗

settings
typenameholling
设置为
typenameholling.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
),我对准备不好的用户json也是安全的?例如,我可以想象Json.NET会因为
$type
信息而创建对象,即使在
MyObject
中找不到相应的字段。

TL/DR:在没有任何明显的
对象
动态
成员的情况下,您可能很安全,但你不能保证安全。为了进一步降低风险,您应遵循以下建议:

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

完整答案

中描述的攻击以及Alvaro Muñoz&Oleksandr Mirosh的攻击都依赖于使用Json.NET的函数来诱使接收方构建一个攻击小工具——一个在构建、填充或处置时会对接收系统造成攻击的类型实例

Json.NET做了两件事来帮助防止此类攻击。首先,它忽略了未知的属性。因此,简单地向JSON有效负载添加一个额外的未知属性,该属性的值包含一个
“$type”
属性,应该不会有什么害处。其次,在反序列化多态值的过程中,在解析
“$type”
属性时,它会检查解析的类型是否与以下内容中的预期类型兼容:

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

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

  • 非类型集合的反序列化。如果您正在反序列化任何类型的非类型集合或字典,如
    ArrayList
    List
    dictionary
    或,则您的系统容易受到集合项中包含的小工具的攻击

  • 从继承的几十个集合中的任意一个的反序列化。此类型早于.Net中泛型的引入,表示一个“半类型”集合,其中项的类型在添加时在运行时进行验证。由于验证发生在构造之后,因此存在一个窗口,可以在其中构造攻击小工具

    显示这一点的示例

  • 反序列化与攻击小工具共享公共基类型或接口的值,而不仅仅是
    对象
    。实现
    ICollection
    IDisposable
    。实现
    INotifyPropertyChanged
    ISupportInitialize
    。如果有任何多态成员或值被声明为这些接口中的任何一个,则易受攻击

  • 实现的类型的反序列化。默认情况下,Json.NET,并且可能是某些外部库中看似无害的类型正在其流式构造函数中反序列化非类型化成员,而您不知道

    一个明显的例子是
    Sytem.Exception
    (或其任何子类型),它反序列化与非类型化字典对应的its中的非类型化字典
    “数据”
    。如果您正在反序列化一个
    异常
    (例如,包含在日志文件中,这是非常常见的),则以下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    
        }
      },
    }
    
    通过设置,无需创建自定义序列化绑定即可减轻攻击。当然,这可能会导致某些.Net类库类型的序列化出现问题

  • 如果设置,则反序列化标记为的类型可能会有类似的问题。但是,默认值为
    true
    ,因此如果不更改此设置,您应该可以

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

    public MyType
    {
        public object tempData;
        public bool ShouldSerializeTempData() { return false; }
    }
    
    得益于Json.NET的功能,
    tempData
    成员将永远不会被序列化,因此您可能会认为您已经清楚了。但如果存在,它将被反序列化!反编译您的代码并注意到这样一个成员的攻击者将能够为
    MyType
    制作一个攻击小工具负载

而这正是我能从脑海中想到的。如你所见,验证
public MyType
{
    public object tempData;
    public bool ShouldSerializeTempData() { return false; }
}