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格式序列化 |
这些格式化器大多实现了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接口的类必须包含序列化构造函数:
[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反序列化攻击向量:
- 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序列化机制和已知漏洞,可以更好地防御反序列化攻击,并安全地使用序列化功能。