我听说有safety questions over the BinaryFormatter.
我从客户端将用户生成的文件发送到服务器。这些是序列化的类,然后由服务器读取。
根据我对上述链接的理解,这很危险。但是我尝试过发送一次性类,甚至尝试了一个实现ISerilizable的类。但由于服务器不知道源程序集,两者都被拒绝了。
[Serializable]
public class Ship : ISerializable
{
public Ship()
{
}
public Ship(SerializationInfo info, StreamingContext context)
{
Console.WriteLine("test");
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
}
}
那么客户端怎么能通过这个向量成功地将代码放入我的服务器?通过伪造命名空间名称和公钥,导致服务器尝试反序列化它,从而运行上面的代码?或者有更微妙的方法来做到这一点?
不幸的是,这个功能是我游戏的核心基础所以我要小心。
答案 0 :(得分:3)
序列化适用于数据,而不是代码。反序列化器从您提供的有效负载中提取数据,构建新的对象实例并从提取的数据中设置对象的值。它不会从有效负载中提取任何代码。
如果您的代码首先容易受到恶意输入的攻击,那么反序列化可能是攻击它的另一种方式 - 就像任何其他注入恶意数据的方式一样。
例如,如果通过连接字符串来构造SQL语句,那么无论字符串来自用户输入还是反序列化数据,您都将容易受到SQL注入攻击。解决此问题的方法是使用参数化查询,而不是避免反序列化或尝试清理用户的输入。
在任何情况下,对原始帖子的回答主要是猜测,对Java序列化的评论与.NET无关或真正做出的例子。
答案 1 :(得分:2)
我知道这是一个老问题,但我对接受的答案不太满意。
<块引用>序列化适用于数据,而不是代码。 [...] 它不会从有效负载中提取任何代码。
事情没那么简单。 BinaryFormatter
使用程序集限定名称来标识类型。在反序列化过程中,这些类型名称由 Type.GetType
解析,它很乐意加载任何程序集。因此,被操纵的流可以加载准备好的程序集,其模块初始化程序会立即执行(但恶意代码也可以放置在序列化构造函数或 [OnDeserializing]
/[OnDeserialized]
方法中)。 This video 演示了如何利用它在浏览器中打开 PowerShell 和网页。
无论如何,原始帖子的答案大多是猜测,对与 .NET 没有真正相关的 Java 序列化的评论或真正人为的示例。
也许只是因为答案太旧了,但今天有很多已知的 BinaryFormatter
攻击。一些例子:
TempFileCollection
可用于删除文件(仅在 .NET Framework 中)。链接视频中也提到了这一点(以及问题中链接的帖子)。StructurelEqualityComparer
可用于导致 StackOverflowException
或极其缓慢的哈希码计算(DoS 攻击)。从 .NET Core 开始,此类型不再可序列化。[Serializable]
的 ISerializable
类型(因此只需设置其字段即可恢复)可以使用无效数据进行初始化。ISerializable
的类型也不会针对所有可能的攻击验证传入的 SerializationInfo
。例如,如果 Dictionary<TKey, TValue>
条目的值被操纵,OutOfMemoryException
可以抛出一个 HashSize
。BinaryFormatter
在更深层次上也很脆弱。例如,数组是在内部处理的(它甚至不能被代理选择器覆盖),并且被操纵的长度信息也会导致 OutOfMemoryException
。我实际上相信 BinaryFormatter
是安全的。我什至在这里打开了一个关于这个主题的问题:https://github.com/dotnet/runtime/issues/50909
但考虑到在实现可序列化类型时从未关注安全性,而且解决所有这些问题将是一项艰巨的任务,我可以理解 BinaryFormatter
在未来版本中将成为 obsoleted。< /p>
虽然我在 SafeMode
中引入了 my binary serializer 选项,但只要可序列化类型本身容易受到攻击,它就不能完全安全。原生支持多种类型只能减少威胁(这也有利于产生very compact payload),但一般无法消除威胁。
结论:只有在同一个进程中同时执行序列化和反序列化时,二进制序列化才是安全的。在任何其他情况下,您都需要实施一些额外的安全措施(例如,通过对流进行加密签名)以确保完全安全。
答案 2 :(得分:1)
BinaryFormatter
序列化字段而不是方法。
传输和加载未知代码的唯一方法是:
Assembly.Load
加载它。CodeDomProvider
在运行时发出IL。