二进制序列化本质上不安全吗?

6

微软警告不要使用 BinaryFormatter(他们写道无法使反序列化安全)。

应用程序应尽快停止使用 BinaryFormatter,即使它们认为正在处理的数据是可信的。

我不想使用基于XMLJson的解决方案(这是他们所指的)。 我关心文件大小和保留对象图。

如果我编写自己的方法遍历对象图并将对象转换为二进制,那么是否可以安全地进行操作?还是从二进制转换成其他格式更危险?


Json/xml有什么异议? - Caius Jard
@Caius Jard 主要关注尺寸和性能。如果问题需要改进,请告诉我。谢谢。 - daglundberg
1
大小 -> 进行gzip压缩。性能 -> 自己编写协议。您应该测试这两个是否真的是问题;对于绝大多数系统来说,显然不是问题;由Web服务器gzip压缩的Json非常普遍。 - Caius Jard
2
为了使二进制序列化安全,需要两个条件:1)当前加载的类型不能被攻击利用;2)在反序列化期间不允许加载程序集。BinaryFormatter 违反了第二个条件,这是一个巨大的安全风险,因为它可能会运行任何代码。第一个条件比较棘手,因为可能存在未发现的漏洞,但.NET Core 在许多有害类型上禁用了[Serializable]。可以随意尝试 我的序列化器,它非常快速并且还支持安全模式。 - György Kőszeg
1个回答

4

是否有二进制(非XML和非JSON)的BinaryFormatter替代品?

这个问题似乎会导致更多基于意见的答案。

我确定有很多库可以用,但也许最知名的替代品是Protocol Buffers(protobuf)。它是Google的一个库,所以得到了充分的开发和关注。然而,并不是每个人都认为使用protobuf进行通用二进制序列化是最好的选择。

如果您想了解更多信息,请在dotnet的github上关注有关BinaryFormatter的讨论,它讨论了BinaryFormatter的一般问题以及protobuf作为替代方案。

我能创建自己的安全二进制序列化系统吗?

可以。话虽如此,真正的问题应该是:“这样做值得我的时间吗?”

请参阅此链接以查看BinaryFormatter的逐步淘汰计划:https://github.com/dotnet/designs/pull/141/commits/bd0a0661f9d248ed31a354d27ad026efd6719690

在底部您将找到:

为什么不使BinaryFormatter适用于不受信任的有效载荷?

BinaryFormatter协议通过指定对象的原始实例字段的值来工作。 换句话说,BinaryFormatter的整个目的是绕过对象的典型构造函数, 并使用私有反射将实例字段设置为通过网络传输而来的内容。以这种方式绕过构造函数意味着对象无法执行任何验证或 保证其内部不变式得到满足。这样做的一个后果是, BinaryFormatter甚至对看似无害的类型如ExceptionList<T>Dictionary<TKey, TValue>(不管TTKeyTValue的实际类型)同样不安全。限制反序列化的允许类型列表无法解决此问题。

安全问题不在于二进制序列化本身;问题在于BinaryFormatter的实现方式。

如果您希望如此,可以设计一个安全的二进制反序列化系统。如果您发送的消息很少,而且可以严密控制反序列化的类型,也许创造一个安全系统并不需要太多的努力。

然而,对于一个足够灵活,能够处理许多不同用例(例如可以反序列化的许多不同类型)的系统,您可能会发现需要花费大量精力来构建足够的安全检查。


值得一提的是,您很可能无法通过一个提供相同广泛实用性(使用案例)且保持安全的系统来达到BinaryFormatter的性能水平,因为BinaryFormatter的速度(部分原因在于)具有非常少的安全特性。您可以通过具有狭窄用例集合的针对性小型系统来接近这样的性能水平。


即使是看似无害的类型,Dictionary<TKey, TValue> 实际上实现了 ISerializable 接口,因此它仍然可以验证输入(但它并没有这样做)。而且,一个自定义序列化器(免责声明:由我编写)可以本地支持常见的集合类型,使它们的序列化既安全又非常紧凑。当然,如果某个字段可能具有无效值,则应避免使用默认的基于字段的序列化。请参见 https://github.com/dotnet/runtime/issues/50909。 - György Kőszeg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接