防止来自恶意 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-&gt;FieldSize(foo, descriptor-&gt;FindFieldByName("Bar")) &lt;= 1024)。 (抱歉,它是 C++ 语法,我从未使用过 .NET 版本,但我猜它非常相似)。 如果需要的话,我确信我们可以添加配额支持...简单地说:还没有。 @Adriano:我不确定 protobuf-net 是否支持此功能而无需解析。 @MarcGravell 谢谢。是计划好的吗?你接受拉取请求吗? @JulienLebosquain 遗憾的是我从未使用过它,所以我不知道它是否支持一切(但我猜它可能是,反射是相当不错的部分)。 【参考方案1】:

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

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

【讨论】:

以上是关于防止来自恶意 protobuf 数据包的 DoS 攻击的主要内容,如果未能解决你的问题,请参考以下文章

防止开放重定向,恶意篡改returnUrl

浅析电商防止恶意下单

浅析电商防止恶意下单

如何防止AD域环境遭受恶意攻击?

解决Sql注入,防止恶意数据

BigQuery 不接受来自 protobuf 的二进制数据