dotnet serialize 101
字数 2850 2025-08-05 08:17:20

.NET 序列化与反序列化安全指南

1. .NET 序列化基础概念

1.1 序列化与反序列化定义

序列化是将对象转换为可存储或传输的格式(如二进制、XML、JSON等)的过程,反序列化则是将这些格式的数据重新构造为对象的过程。在.NET中,序列化主要用于:

  • 对象持久化(存储到文件或数据库)
  • 跨应用程序域通信
  • 远程方法调用(RPC)
  • Web服务数据传输

1.2 序列化特性

在.NET中,使用[Serializable]特性标记可序列化的类,类似于Java中的Serializable接口:

[Serializable]
public class MyObject
{
    public int n1;
    [NonSerialized] 
    public int n2;  // 标记为不序列化
    public String str;
}

[NonSerialized]特性用于标记不应被序列化的字段。

2. .NET 序列化实现

2.1 基本序列化示例

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

public static void BinaryFormatterSerialize(string file, object o)
{
    BinaryFormatter binaryFormatter = new BinaryFormatter();
    FileStream fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None);
    binaryFormatter.Serialize(fileStream, o);
    fileStream.Close();
}

public static object BinaryFormatterDeserialFromFile(string file)
{
    IFormatter formatter = new BinaryFormatter();
    Stream stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
    object o = formatter.Deserialize(stream);
    stream.Close();
    return o;
}

2.2 主要格式化器(Formatter)

.NET提供了多种格式化器,每种对应不同的序列化格式:

格式化器 格式 描述
BinaryFormatter 二进制 二进制格式序列化
SoapFormatter SOAP SOAP格式序列化
LosFormatter 二进制 用于Web窗体页的视图状态序列化
ObjectStateFormatter 二进制 序列化状态对象图
XmlSerializer XML XML格式序列化
JsonSerializer JSON JSON格式序列化

这些格式化器大多实现了IFormatterIRemotingFormatter接口。

3. 序列化生命周期与高级控制

3.1 IFormatter接口关键字段

IFormatter接口定义了三个重要字段:

  1. SurrogateSelector (ISurrogateSelector):序列化代理选择器,可接管序列化/反序列化处理
  2. Binder (SerializationBinder):控制在序列化和反序列化期间使用的实际类型
  3. Context (StreamingContext):序列化流上下文,包含来源和目的地信息

3.2 序列化生命周期

当调用Serialize方法时,生命周期如下:

  1. 检查是否有代理选择器,有则检查是否处理当前对象类型
    • 如果处理,调用ISerializable.GetObjectData()
  2. 如果没有代理选择器或不处理该类型:
    • 检查对象是否有[Serializable]特性,没有则抛出异常
    • 检查是否实现ISerializable接口,实现则调用其GetObjectData方法
    • 否则使用默认序列化策略,序列化所有未标记[NonSerialized]的字段

3.3 序列化回调事件

.NET提供了四个回调事件特性:

特性 调用时机 典型用途
[OnDeserializing] 反序列化之前 初始化可选字段默认值
[OnDeserialized] 反序列化之后 根据其他字段修改可选字段值
[OnSerializing] 序列化之前 准备序列化,创建可选数据结构
[OnSerialized] 序列化之后 记录序列化事件

3.4 ISerializable接口

实现ISerializable接口的类必须包含序列化构造函数:

[Serializable]
public class MyObject : ISerializable
{
    public string str { get; set; }
    
    protected MyObject(SerializationInfo info, StreamingContext context)
    {
        str = info.GetString("str");
    }
    
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("str", str, typeof(string));
    }
}

3.5 序列化代理(Serialization Surrogate)

代理选择器可以完全控制序列化和反序列化过程:

class MySerializationSurrogate : ISerializationSurrogate
{
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        info.AddValue("str", ((MyObject)obj).str);
    }
    
    public object SetObjectData(object obj, SerializationInfo info, 
                              StreamingContext context, ISurrogateSelector selector)
    {
        MyObject m = new MyObject();
        m.str = (string)info.GetValue("str", typeof(string));
        return m;
    }
}

使用代理选择器:

SurrogateSelector ss = new SurrogateSelector();
ss.AddSurrogate(typeof(MyObject), binaryFormatter.Context, new MySerializationSurrogate());
binaryFormatter.SurrogateSelector = ss;

4. 反序列化漏洞与ysoserial.net

4.1 常见攻击向量(Gadgets)

ysoserial.net工具中包含了多种已知的.NET反序列化攻击向量:

  1. ActivitySurrogateSelector:绕过.NET 4.8+类型保护
  2. ObjectDataProvider:通过WPF的ObjectDataProvider执行代码
  3. TextFormattingRunProperties:通常生成最短的payload
  4. TypeConfuseDelegate:通过委托混淆执行代码
  5. WindowsIdentity:利用Windows身份标识执行代码

4.2 支持的格式化器

不同攻击向量支持不同的格式化器:

Gadget 支持的格式化器
ActivitySurrogateSelector BinaryFormatter, LosFormatter, SoapFormatter
ObjectDataProvider DataContractSerializer, FastJson, FsPickler, JavaScriptSerializer, Json.Net, Xaml, XmlSerializer
TypeConfuseDelegate BinaryFormatter, LosFormatter, NetDataContractSerializer

4.3 ysoserial.net插件

除了核心攻击向量,ysoserial.net还提供针对特定应用的插件:

  1. ActivatorUrl:向远程激活对象发送payload
  2. ApplicationTrust:生成ApplicationTrust类的XML payload
  3. Clipboard:生成DataObject并复制到剪贴板
  4. DotNetNuke:针对CVE-2017-9822的payload
  5. SharePoint:针对SharePoint多个CVE的payload

5. 安全建议

  1. 避免使用不安全的格式化器:特别是BinaryFormatterLosFormatterSoapFormatter
  2. 使用安全序列化替代方案:如JsonSerializerXmlSerializer
  3. 实现SerializationBinder:限制反序列化的类型
  4. 验证输入数据:对所有反序列化的数据进行严格验证
  5. 保持更新:及时应用.NET框架的安全更新

6. 深入研究方向

  1. 分析各Gadget的工作原理:如TypeConfuseDelegate如何利用委托混淆
  2. 研究特定格式化器的漏洞:如BinaryFormatter的已知漏洞
  3. 探索防御技术:如使用SerializationBinder进行类型限制
  4. 研究特定应用的序列化漏洞:如SharePoint、DotNetNuke等

通过深入理解.NET序列化机制和已知漏洞,可以更好地防御反序列化攻击,并安全地使用序列化功能。

.NET 序列化与反序列化安全指南 1. .NET 序列化基础概念 1.1 序列化与反序列化定义 序列化是将对象转换为可存储或传输的格式(如二进制、XML、JSON等)的过程,反序列化则是将这些格式的数据重新构造为对象的过程。在.NET中,序列化主要用于: 对象持久化(存储到文件或数据库) 跨应用程序域通信 远程方法调用(RPC) Web服务数据传输 1.2 序列化特性 在.NET中,使用 [Serializable] 特性标记可序列化的类,类似于Java中的 Serializable 接口: [NonSerialized] 特性用于标记不应被序列化的字段。 2. .NET 序列化实现 2.1 基本序列化示例 2.2 主要格式化器(Formatter) .NET提供了多种格式化器,每种对应不同的序列化格式: | 格式化器 | 格式 | 描述 | |---------|------|------| | BinaryFormatter | 二进制 | 二进制格式序列化 | | SoapFormatter | SOAP | SOAP格式序列化 | | LosFormatter | 二进制 | 用于Web窗体页的视图状态序列化 | | ObjectStateFormatter | 二进制 | 序列化状态对象图 | | XmlSerializer | XML | XML格式序列化 | | JsonSerializer | JSON | JSON格式序列化 | 这些格式化器大多实现了 IFormatter 或 IRemotingFormatter 接口。 3. 序列化生命周期与高级控制 3.1 IFormatter接口关键字段 IFormatter 接口定义了三个重要字段: SurrogateSelector ( ISurrogateSelector ):序列化代理选择器,可接管序列化/反序列化处理 Binder ( SerializationBinder ):控制在序列化和反序列化期间使用的实际类型 Context ( StreamingContext ):序列化流上下文,包含来源和目的地信息 3.2 序列化生命周期 当调用 Serialize 方法时,生命周期如下: 检查是否有代理选择器,有则检查是否处理当前对象类型 如果处理,调用 ISerializable.GetObjectData() 如果没有代理选择器或不处理该类型: 检查对象是否有 [Serializable] 特性,没有则抛出异常 检查是否实现 ISerializable 接口,实现则调用其 GetObjectData 方法 否则使用默认序列化策略,序列化所有未标记 [NonSerialized] 的字段 3.3 序列化回调事件 .NET提供了四个回调事件特性: | 特性 | 调用时机 | 典型用途 | |------|---------|---------| | [OnDeserializing] | 反序列化之前 | 初始化可选字段默认值 | | [OnDeserialized] | 反序列化之后 | 根据其他字段修改可选字段值 | | [OnSerializing] | 序列化之前 | 准备序列化,创建可选数据结构 | | [OnSerialized] | 序列化之后 | 记录序列化事件 | 3.4 ISerializable接口 实现 ISerializable 接口的类必须包含序列化构造函数: 3.5 序列化代理(Serialization Surrogate) 代理选择器可以完全控制序列化和反序列化过程: 使用代理选择器: 4. 反序列化漏洞与ysoserial.net 4.1 常见攻击向量(Gadgets) ysoserial.net工具中包含了多种已知的.NET反序列化攻击向量: ActivitySurrogateSelector :绕过.NET 4.8+类型保护 ObjectDataProvider :通过WPF的ObjectDataProvider执行代码 TextFormattingRunProperties :通常生成最短的payload TypeConfuseDelegate :通过委托混淆执行代码 WindowsIdentity :利用Windows身份标识执行代码 4.2 支持的格式化器 不同攻击向量支持不同的格式化器: | Gadget | 支持的格式化器 | |--------|---------------| | ActivitySurrogateSelector | BinaryFormatter, LosFormatter, SoapFormatter | | ObjectDataProvider | DataContractSerializer, FastJson, FsPickler, JavaScriptSerializer, Json.Net, Xaml, XmlSerializer | | TypeConfuseDelegate | BinaryFormatter, LosFormatter, NetDataContractSerializer | 4.3 ysoserial.net插件 除了核心攻击向量,ysoserial.net还提供针对特定应用的插件: ActivatorUrl :向远程激活对象发送payload ApplicationTrust :生成ApplicationTrust类的XML payload Clipboard :生成DataObject并复制到剪贴板 DotNetNuke :针对CVE-2017-9822的payload SharePoint :针对SharePoint多个CVE的payload 5. 安全建议 避免使用不安全的格式化器 :特别是 BinaryFormatter 、 LosFormatter 和 SoapFormatter 使用安全序列化替代方案 :如 JsonSerializer 或 XmlSerializer 实现SerializationBinder :限制反序列化的类型 验证输入数据 :对所有反序列化的数据进行严格验证 保持更新 :及时应用.NET框架的安全更新 6. 深入研究方向 分析各Gadget的工作原理 :如 TypeConfuseDelegate 如何利用委托混淆 研究特定格式化器的漏洞 :如 BinaryFormatter 的已知漏洞 探索防御技术 :如使用 SerializationBinder 进行类型限制 研究特定应用的序列化漏洞 :如SharePoint、DotNetNuke等 通过深入理解.NET序列化机制和已知漏洞,可以更好地防御反序列化攻击,并安全地使用序列化功能。