【问题标题】:Preventing DoS attacks from malicious protobuf packets防止来自恶意 protobuf 数据包的 DoS 攻击
【发布时间】: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 遗憾的是我从未使用过它,所以我不知道它是否支持一切(但我猜它可能是,反射是相当不错的部分)。

标签: .net security protobuf-net


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多