防止来自恶意protobuf数据包的DoS攻击

时间:2014-04-30 12:47:00

标签: .net security protobuf-net

我目前正在编写客户端/服务器应用程序,使用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个元素,等等。

是否有任何简单的解决方案可以防止我错过的这个问题(而不是自己实现或分叉)?

1 个答案:

答案 0 :(得分:0)

目前我看到的唯一两个选项是深入研究Protobuf-Nets代码库并找到它解析二进制数据的位置。如果您计划使用协议缓冲区,这并不是一个坏主意。

或者您可以为具有静态设置长度(非动态)的字符串/列表/数组创建自己的类,因此您不会通过Internet发送长度前缀,这会破坏使用Protobuf等高效系统的目的并弄乱了你的建筑。