在 .NET 9.0 中启用二进制序列化:配置、风险与替代方案
- 引言
- 一、启用二进制序列化的步骤
- 二、实现序列化与反序列化
- 三、安全风险与缓解措施
- 四、推荐替代方案
- 五、总结
引言
在 .NET 生态中,二进制序列化(Binary Serialization)曾是实现对象持久化和跨进程通信的常用技术。然而,自 .NET 5 起,BinaryFormatter
因安全漏洞被标记为过时,并在默认配置下禁用。对于仍需在 .NET 9.0 中使用此功能的开发者,本文将详细解析启用步骤、潜在风险及推荐替代方案。
一、启用二进制序列化的步骤
修改项目配置
在 .csproj
文件中添加以下配置,解除 BinaryFormatter
的限制:
<PropertyGroup><EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>
注意:
此配置会触发编译警告 SYSLIB0011
,需开发者显式接受安全风险。
仅建议在完全可控的环境中使用(如内部工具或遗留系统迁移)。
标记可序列化类型
为需要序列化的类添加 [Serializable]
特性:
[Serializable]
public class Person {
public string Name { get; set; }
[NonSerialized]
public int SecretCode; // 此字段不会被序列化
二、实现序列化与反序列化
序列化对象
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;public byte[] Serialize(object obj)
{using (var stream = new MemoryStream()) {var formatter = new BinaryFormatter();formatter.Serialize(stream, obj);return stream.ToArray();}
}
反序列化对象
public T Deserialize<T>(byte[] data)
{using (var stream = new MemoryStream(data)) {var formatter = new BinaryFormatter();return (T)formatter.Deserialize(stream);}
}
关键问题:
反序列化时需确保目标类型 T
与原始类型完全匹配(包括程序集版本),否则会抛出 SerializationException
。
三、安全风险与缓解措施
已知风险
反序列化漏洞:攻击者可构造恶意数据触发代码执行(如 ISerializable
接口滥用)。
类型注入:反序列化不受信任数据可能导致意外类型加载。
缓解建议
数据来源可信:仅反序列化来自可信源(如内部系统生成)的数据。
输入验证:对反序列化前的字节流进行签名或校验。
沙箱隔离:在独立 AppDomain
中执行反序列化操作。
四、推荐替代方案
System.Text.Json
特点:高性能、低内存分配,支持异步序列化。
场景:REST API、跨平台数据交换。
var json = JsonSerializer.Serialize(obj);
var obj = JsonSerializer.Deserialize<T>(json);
Protobuf-net
特点:紧凑二进制格式,高效且类型安全。
场景:高性能通信(如 gRPC)、大数据持久化。
using ProtoBuf;
[ProtoContract]
public class Person {[ProtoMember(1)]public string Name { get; set; }
XML 序列化
特点:可读性强,支持 XML 架构验证。
场景:配置文件、与旧系统兼容。
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(stream, obj);
五、总结
尽管 .NET 9.0 仍支持通过配置启用 BinaryFormatter
,但其高安全风险和版本兼容性问题使其不再适用于现代应用。建议优先选择 System.Text.Json
或 Protobuf-net
等替代方案。若必须使用二进制序列化,请严格遵循以下原则:
仅处理可信数据源。
隔离反序列化操作环境。
监控并更新依赖库以修复潜在漏洞。
技术演进提示:微软已明确表示未来版本可能彻底移除 BinaryFormatter
,建议尽早制定迁移计划。
// 历史终将淘汰旧技术,但我们可以优雅地过渡。
pragma warning disable SYSLIB0011var legacyData = oldFormatter.Deserialize(stream);
pragma warning restore SYSLIB0011