我目前正在编写客户端/服务器应用程序,使用Google Protocol Buffers对底层消息进行编码。由于它是一个.NET程序,我使用的是protobuf-net库:它快速,便携且经过深思熟虑。
但是,我有点担心潜在的DoS攻击。服务器应用程序将直接面向Internet,底层协议将公开记录。攻击者可以很容易地制作一个数据包来耗尽内存。
一个简单的例子:
给出以下原型定义:
[ProtoContract]
class Foo {
[ProtoMember(1)]
public string Bar { get; set; }
}
以下代码将尝试为Bar
字符串分配2GB缓冲区:
byte[] bytes = { 0x0A, 0xFF, 0xFF, 0xFF, 0xFF, 0x07 };
Serializer.Deserialize<Foo>(new MemoryStream(bytes));
立即产生OutOfMemoryException
。当然,这里真的很重要:运行时无法分配它(至少在32位进程中)。现在制作多个数据包,每个数据包分配几百MB的内存,并且由于缺少内存而观察正常操作失败。当然,如果攻击者在字符串长度之后没有发送任何内容,GC将迅速回收内存,但它仍然太容易增加内存压力。
我知道这个问题并不是真正特定于protobuf-net的:任何使用长度前缀数据的协议都可能会遇到同样的问题。通常,他们使用任意配额来解决。但是,我没有找到任何方法在protobuf-net中指定它们。例如,我想指定一个字符串不能超过N个字符,给定列表不能有更多M个元素,等等。
是否有任何简单的解决方案可以防止我错过的这个问题(而不是自己实现或分叉)?
答案 0 :(得分:0)
目前我看到的唯一两个选项是深入研究Protobuf-Nets代码库并找到它解析二进制数据的位置。如果您计划使用协议缓冲区,这并不是一个坏主意。
或者您可以为具有静态设置长度(非动态)的字符串/列表/数组创建自己的类,因此您不会通过Internet发送长度前缀,这会破坏使用Protobuf等高效系统的目的并弄乱了你的建筑。