C#的BinaryFormatter如何序列化对象?

小老鼠
发布: 2025-08-05 09:27:02
原创
655人浏览过

binaryformatter在.net 5+中被弃用,因其反序列化机制存在严重安全风险,可能被利用执行远程代码;2. 使用它时必须确保类标记[serializable],通过流进行序列化与反序列化操作,并可借助[nonserialized]控制字段;3. 其主要风险在于反序列化不可信数据时可能触发恶意类型实例化,形成反序列化漏洞;4. 推荐替代方案包括system.text.json、newtonsoft.json、protobuf和messagepack,它们更安全高效;5. 仅在遗留系统或完全可信环境中才应考虑使用binaryformatter;6. 若必须使用,应通过serializationbinder限制类型、校验数据完整性、遵循最小权限原则并尽快迁移到现代方案,以降低风险,但根本解决之道是停止使用。

C#的BinaryFormatter如何序列化对象?

C#中的

BinaryFormatter
登录后复制
,它提供了一种将对象转换为字节流(序列化)以便存储或传输,然后再将字节流恢复为对象(反序列化)的机制。从我的个人经验来看,它曾经是一个方便的工具,尤其在早期.NET框架中,用于将对象状态持久化到文件或在AppDomain之间传递数据。但随着技术发展和安全意识的提升,它现在已经是一个被明确不推荐使用的“遗留”方案了,尤其是在处理来自不可信源的数据时,它的风险远大于便利。

在实际操作中,使用

BinaryFormatter
登录后复制
来序列化一个对象,核心在于几个步骤:首先,你得确保你的对象类被标记为可序列化;接着,你需要一个流(比如文件流或内存流)来承载序列化后的字节数据;最后,通过
BinaryFormatter
登录后复制
的实例调用相应的方法。


将C#对象通过

BinaryFormatter
登录后复制
进行序列化,主要涉及以下几个步骤和注意事项:

1. 标记可序列化类型: 你的类必须使用

[Serializable]
登录后复制
特性进行标记。这是
BinaryFormatter
登录后复制
识别一个类型是否允许被序列化的前提。

[Serializable]
public class MyDataObject
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreatedDate { get; set; }

    // 这个字段不会被序列化
    [NonSerialized]
    public string TempInfo; 

    public MyDataObject(int id, string name)
    {
        Id = id;
        Name = name;
        CreatedDate = DateTime.Now;
        TempInfo = "这是一个临时信息";
    }

    public override string ToString()
    {
        return $"Id: {Id}, Name: {Name}, Created: {CreatedDate}, TempInfo (NonSerialized): {TempInfo}";
    }
}
登录后复制

2. 序列化对象: 你需要一个

BinaryFormatter
登录后复制
的实例和一个
Stream
登录后复制
对象。通常会用
FileStream
登录后复制
来写入文件,或者
MemoryStream
登录后复制
在内存中操作。

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization; // For ISerializable if needed

// 创建一个要序列化的对象实例
MyDataObject originalObject = new MyDataObject(101, "示例数据");
Console.WriteLine($"原始对象: {originalObject}");

// 序列化到文件
string filePath = "mydata.bin";
try
{
    using (FileStream fs = new FileStream(filePath, FileMode.Create))
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(fs, originalObject);
    }
    Console.WriteLine($"对象已序列化到 {filePath}");
}
catch (SerializationException e)
{
    Console.WriteLine($"序列化失败: {e.Message}");
}
catch (Exception e)
{
    Console.WriteLine($"发生未知错误: {e.Message}");
}
登录后复制

3. 反序列化对象: 反序列化是将字节流重新转换回对象的过程。同样需要一个

BinaryFormatter
登录后复制
实例和从文件或内存中读取的
Stream
登录后复制

MyDataObject deserializedObject = null;
try
{
    using (FileStream fs = new FileStream(filePath, FileMode.Open))
    {
        BinaryFormatter formatter = new BinaryFormatter();
        // 关键点:反序列化时,你必须非常信任数据的来源!
        deserializedObject = (MyDataObject)formatter.Deserialize(fs);
    }
    Console.WriteLine($"对象已从 {filePath} 反序列化成功。");
    Console.WriteLine($"反序列化对象: {deserializedObject}");

    // 注意:TempInfo 字段因为 [NonSerialized] 而不会被保留其值,会是其默认值(null)
    // 这就是为什么原始对象的 TempInfo 有值,而反序列化后会是 null
    if (deserializedObject.TempInfo == null)
    {
        Console.WriteLine("注意: TempInfo 字段因为被标记为 [NonSerialized] 而没有被序列化/反序列化。");
    }
}
catch (SerializationException e)
{
    Console.WriteLine($"反序列化失败: {e.Message}");
}
catch (Exception e)
{
    Console.WriteLine($"发生未知错误: {e.Message}");
}
登录后复制

4. 控制序列化行为(可选): 如果你需要更精细地控制序列化过程,例如在序列化时排除特定字段,或者在反序列化时进行一些自定义初始化,可以实现

ISerializable
登录后复制
接口。这会让你自己编写
GetObjectData
登录后复制
和特殊的构造函数来处理序列化和反序列化逻辑。但这通常会增加复杂性,并且在现代应用中,我们有更多推荐的替代方案。


BinaryFormatter
登录后复制
为何在.NET 5+中被弃用?其潜在的安全风险是什么?

BinaryFormatter
登录后复制
的弃用并非偶然,而是源于其固有的、难以规避的安全漏洞。核心问题在于,它在反序列化时会尝试实例化并执行字节流中描述的任何类型,这其中就包括了潜在的恶意类型。如果攻击者能够控制输入到
BinaryFormatter
登录后复制
的字节流,他们就可以构造一个恶意的“gadget chain”(小工具链),这个链条由一系列看似无害的对象组成,但当它们被
BinaryFormatter
登录后复制
按特定顺序实例化并连接起来时,就会触发意想不到的副作用,例如执行任意代码。

这被称为“反序列化漏洞”,它是一个臭名昭著的远程代码执行(RCE)向量。想象一下,你的应用程序从网络接收到一段数据,然后天真地使用

BinaryFormatter
登录后复制
去反序列化它。如果这段数据是攻击者精心构造的恶意负载,你的应用程序就会在不知不觉中执行攻击者指定的代码,这可能导致数据泄露、系统破坏甚至完全控制。由于
BinaryFormatter
登录后复制
的设计机制,即使不使用
[Serializable]
登录后复制
特性,攻击者也可能通过反射等手段绕过一些限制。因此,微软在.NET 5及更高版本中明确将其标记为过时,并强烈建议开发者停止使用它,尤其是在处理任何来自不可信源的数据时。这不仅仅是建议,更是对开发者安全责任的警示。


替代
BinaryFormatter
登录后复制
的现代序列化方案有哪些?

鉴于

BinaryFormatter
登录后复制
的安全隐患,现代.NET开发中,我们有更多安全且高效的序列化选择。这些替代方案不仅在安全性上更有保障,通常在性能、跨平台兼容性以及易用性上也有显著优势:

  • System.Text.Json
    登录后复制
    (推荐):这是.NET Core 3.0及以后版本内置的高性能JSON序列化器。它专注于JSON格式,性能卓越,内存占用低,并且默认是安全的(不会反序列化任意类型)。它非常适合Web API、前后端数据交换以及配置文件的存储。其基于合约(Contract-based)的序列化方式,也提供了很好的控制粒度。

  • Newtonsoft.Json (Json.NET):作为事实上的.NET JSON序列化标准,

    Newtonsoft.Json
    登录后复制
    System.Text.Json
    登录后复制
    出现之前几乎是所有.NET项目的首选。它功能强大,灵活度极高,支持各种复杂的序列化场景,包括自定义转换器、LINQ to JSON等。虽然
    System.Text.Json
    登录后复制
    在某些基准测试中可能更快,但
    Newtonsoft.Json
    登录后复制
    凭借其丰富的功能集和成熟的生态系统,在很多现有项目中依然被广泛使用。

  • Google Protocol Buffers (Protobuf):如果你的应用对性能和数据包大小有极高要求,并且需要跨语言通信,Protobuf是一个非常优秀的二进制序列化方案。它通过定义

    .proto
    登录后复制
    文件来描述数据结构,然后生成对应语言的代码,序列化后的数据非常紧凑,解析速度快。它在微服务、高性能计算和移动应用等领域非常流行。

  • MessagePack for C#:类似于Protobuf,MessagePack也是一种高效的二进制序列化格式。它以其极快的序列化/反序列化速度和紧凑的数据格式而闻名,并且支持Schema-less(无模式)序列化,这在某些场景下提供了更大的灵活性。

  • System.Xml.Serialization.XmlSerializer
    登录后复制
    /
    System.Runtime.Serialization.DataContractSerializer
    登录后复制
    :这两种是XML序列化器。
    XmlSerializer
    登录后复制
    主要用于将对象序列化为符合特定XML Schema定义的XML文档,常见于SOAP Web服务和旧式集成。
    DataContractSerializer
    登录后复制
    则更侧重于数据契约(Data Contract)的概念,通常与WCF服务一起使用,它提供了更好的版本容忍性。虽然它们仍然有效,但在新项目中,XML通常不如JSON或二进制格式流行。

选择哪种方案,取决于你的具体需求:是需要人类可读性、跨平台兼容性、极致性能,还是与其他系统互操作。

序列猴子开放平台
序列猴子开放平台

具有长序列、多模态、单模型、大数据等特点的超大规模语言模型

序列猴子开放平台0
查看详情 序列猴子开放平台

在什么情况下仍然可能需要使用
BinaryFormatter
登录后复制
?以及如何降低其潜在风险?

尽管

BinaryFormatter
登录后复制
已被弃用,但在某些特定且受限的场景下,你可能仍然会遇到或不得不使用它。这通常发生在以下情况:

  • 遗留系统集成:你正在维护或与一个历史悠久的.NET应用程序交互,该程序在设计之初就大量依赖

    BinaryFormatter
    登录后复制
    来存储数据(例如,将对象序列化到文件、数据库BLOB字段)或进行进程间通信。在这种情况下,短期内完全重构所有序列化逻辑可能成本过高或不可行。

  • 受控且高度信任的环境:在极少数情况下,如果你的应用程序运行在一个完全隔离、数据来源绝对可信的环境中(例如,仅用于应用程序内部的、进程内的数据传递,且数据完全由你自己的代码生成和消费,没有任何外部输入),并且你完全了解其风险,理论上可以使用。但这仍然不推荐,因为即使是内部数据,也可能因程序漏洞导致数据被篡改。

如何降低潜在风险(如果必须使用):

请注意,以下措施并不能完全消除

BinaryFormatter
登录后复制
的固有风险,它们只是在特定限制下提供一些缓解。最根本的原则是:绝不反序列化来自不可信源的数据!

  1. 限制反序列化的类型(

    SerializationBinder
    登录后复制
    :这是最有效的缓解措施之一。你可以自定义一个继承自
    SerializationBinder
    登录后复制
    的类,并重写其
    BindToType
    登录后复制
    方法。在这个方法中,你可以严格限制允许反序列化的类型列表。如果尝试反序列化的类型不在你的白名单中,就抛出异常。

    public sealed class WhitelistSerializationBinder : SerializationBinder
    {
        public override Type BindToType(string assemblyName, string typeName)
        {
            // 严格限制只允许反序列化 MyDataObject 类型
            // 注意:这里需要完整的类型名称,包括命名空间和程序集信息
            if (typeName == "YourNamespace.MyDataObject" && assemblyName.StartsWith("YourAssemblyName,"))
            {
                return Type.GetType($"{typeName}, {assemblyName}");
            }
            // 阻止反序列化其他任何类型
            throw new SerializationException($"不允许反序列化类型: {typeName}, {assemblyName}");
        }
    }
    
    // 使用时:
    // formatter.Binder = new WhitelistSerializationBinder();
    // deserializedObject = (MyDataObject)formatter.Deserialize(fs);
    登录后复制

    这个方法可以有效阻止恶意类型被实例化,但它要求你对所有可能被序列化的类型有清晰的白名单。

  2. 数据完整性校验:在反序列化之前,对数据流进行完整性校验,例如通过计算哈希值并与已知安全哈希值进行比对。如果哈希值不匹配,则拒绝反序列化。这可以防止数据在传输或存储过程中被篡改,但无法阻止攻击者构造新的恶意负载。

  3. 最小权限原则:运行序列化/反序列化代码的进程,应以尽可能低的权限运行,限制其对文件系统、网络或其他资源的访问能力。即使发生RCE,也能限制其造成的损害。

  4. 隔离处理:如果可能,将

    BinaryFormatter
    登录后复制
    的反序列化操作放在一个独立的、沙箱化的进程中。即使该进程被攻破,也难以影响到主应用程序或其他关键系统。

  5. 尽快迁移:以上所有措施都是权宜之计。长远来看,最根本的解决方案是逐步将所有使用

    BinaryFormatter
    登录后复制
    的序列化逻辑迁移到更现代、更安全的替代方案(如
    System.Text.Json
    登录后复制
    或Protobuf)。这可能需要投入时间和资源,但从安全性和维护性角度来看,这是值得的。

记住,安全是一个持续的过程,而不是一劳永逸的解决方案。对于像

BinaryFormatter
登录后复制
这样已知存在高风险的工具,除非万不得已,否则应坚决避免使用。

以上就是C#的BinaryFormatter如何序列化对象?的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号