防止来自恶意 protobuf 数据包的 DoS 攻击
Posted
技术标签:
【中文标题】防止来自恶意 protobuf 数据包的 DoS 攻击【英文标题】:Preventing DoS attacks from malicious protobuf packets 【发布时间】:2014-06-16 19:11:20 【问题描述】:我目前正在编写一个客户端/服务器应用程序,使用 Google 协议缓冲区对底层消息进行编码。由于它是一个 .NET 程序,我使用的是 protobuf-net 库:它快速、便携且经过深思熟虑。
但是,我有点担心潜在的 DoS 攻击。服务器应用程序将直接面向互联网,并且底层协议将被公开记录。攻击者可以很容易地制作一个数据包来耗尽内存。
一个简单的例子:
给定以下原型定义:
[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 个元素等等。
是否有任何简单的解决方案来防止我错过的这个问题(而不是自己实现或分叉)?
【问题讨论】:
我不知道是否有更好的方法,AFAIK 如果你放弃 normal 解析并使用 reflection i>(至少作为早期验证):reflection->FieldSize(foo, descriptor->FindFieldByName("Bar")) <= 1024)
。 (抱歉,它是 C++ 语法,我从未使用过 .NET 版本,但我猜它非常相似)。
如果需要的话,我确信我们可以添加配额支持...简单地说:还没有。
@Adriano:我不确定 protobuf-net 是否支持此功能而无需解析。
@MarcGravell 谢谢。是计划好的吗?你接受拉取请求吗?
@JulienLebosquain 遗憾的是我从未使用过它,所以我不知道它是否支持一切(但我猜它可能是,反射是相当不错的部分)。
【参考方案1】:
目前,我为您看到的唯一两个选择是深入研究 Protobuf-Nets 代码库并找到它解析二进制数据的位置。如果您打算使用协议缓冲区,这并不是一个坏主意。
或者您可以为具有静态设置长度(非动态)的字符串/列表/数组创建自己的类,这样您就不会通过 Internet 发送长度前缀,这违背了使用 Protobuf 等高效系统的目的并弄乱你的架构。
【讨论】:
以上是关于防止来自恶意 protobuf 数据包的 DoS 攻击的主要内容,如果未能解决你的问题,请参考以下文章