Google Protocol Buffers C++ 实现在面对恶意数据时的稳定性和安全性
Google Protocol Buffers C++ implementation stability and security in the face of malicious data
对于那些使用过 Google Protocol Buffers C++ 实现的人来说,它如何处理恶意或格式错误的消息?例如,它会崩溃还是继续运行?我的应用程序肯定会在某个时候收到恶意数据,我不希望每次收到格式错误的消息时它都崩溃。这是我在这个问题上能找到的唯一答案 (google mailing list)。
There was a review specifically for security issues before the code was released. For at least the C++ and Java implementations, there are various safeguards to protect against corrupt or malicious data. There are limits on the overall message size provided by the protobuf library as well (CodedInputStream::SetTotalBytesLimit); it also provides a recursion limit to prevent deeply nested messages from blowing the stack. There are other internal implementation details to avoid things like memory exhaustion (most specifically from receiving messages that indicate a huge length-delimited value).
我在非常 security-conscious web-facing 的应用程序中使用 c++ google 协议缓冲区。
查看生成的代码,所有反序列化工作都委托给每个消息的 <Message-Type>::MergePartialFromCodedStream
方法中的 auto-generated 代码。这些方法是通过对数据类型和长度进行全面检查而生成的,到目前为止我们没有遇到任何问题。
您可能想要自己关闭的一个攻击领域是 protobuf 数据的框架 - 协议缓冲区本身不会以任何类型的标准化方式将序列化消息的整体大小序列化到流中 header ,因此您可能希望(像我一样)将所有协议缓冲区消息包装在一个帧中。出于我的目的,帧 header 仅包含一个消息大小,这意味着我能够在尝试从网络上读取消息之前确定消息的内存要求,更不用说对其进行解码了。
此时可以进行一个简单的检查,如果大小过大则拒绝邮件(或断开连接)。
可以做进一步的工作,将此框架包装在 public 密钥包络方案中,以防止 man-in-the-middle 劫持您的 session 如果这是一个问题。
消息中的缓冲区溢出(例如字符串太长)不会发生,因为 bytes
和 string
字段在内部由 std::string
表示,这会自动增加其内存占用因为数据附加到它。
然而:
无法保证恶意客户端不会试图对包含无效数据的有效消息进行编码。例如,如果您的服务器应用程序从数据字符串中获取一个方法名称,查找它的地址并调用它,那么这就是一个明显的攻击向量。
在未全面检查是否明确允许该操作的情况下,切勿允许客户端数据查找服务器代码。
一些绝不能做的例子:
- 允许客户端在文本字段中向您发送 SQL
- 允许客户端向您发送 command-lines,您随后将其传递给
system()
、exec()
、spawn()
等...
- 允许客户端向您发送共享库的名称和其中的函数名称...
等等。
对于那些使用过 Google Protocol Buffers C++ 实现的人来说,它如何处理恶意或格式错误的消息?例如,它会崩溃还是继续运行?我的应用程序肯定会在某个时候收到恶意数据,我不希望每次收到格式错误的消息时它都崩溃。这是我在这个问题上能找到的唯一答案 (google mailing list)。
There was a review specifically for security issues before the code was released. For at least the C++ and Java implementations, there are various safeguards to protect against corrupt or malicious data. There are limits on the overall message size provided by the protobuf library as well (CodedInputStream::SetTotalBytesLimit); it also provides a recursion limit to prevent deeply nested messages from blowing the stack. There are other internal implementation details to avoid things like memory exhaustion (most specifically from receiving messages that indicate a huge length-delimited value).
我在非常 security-conscious web-facing 的应用程序中使用 c++ google 协议缓冲区。
查看生成的代码,所有反序列化工作都委托给每个消息的 <Message-Type>::MergePartialFromCodedStream
方法中的 auto-generated 代码。这些方法是通过对数据类型和长度进行全面检查而生成的,到目前为止我们没有遇到任何问题。
您可能想要自己关闭的一个攻击领域是 protobuf 数据的框架 - 协议缓冲区本身不会以任何类型的标准化方式将序列化消息的整体大小序列化到流中 header ,因此您可能希望(像我一样)将所有协议缓冲区消息包装在一个帧中。出于我的目的,帧 header 仅包含一个消息大小,这意味着我能够在尝试从网络上读取消息之前确定消息的内存要求,更不用说对其进行解码了。
此时可以进行一个简单的检查,如果大小过大则拒绝邮件(或断开连接)。
可以做进一步的工作,将此框架包装在 public 密钥包络方案中,以防止 man-in-the-middle 劫持您的 session 如果这是一个问题。
消息中的缓冲区溢出(例如字符串太长)不会发生,因为 bytes
和 string
字段在内部由 std::string
表示,这会自动增加其内存占用因为数据附加到它。
然而:
无法保证恶意客户端不会试图对包含无效数据的有效消息进行编码。例如,如果您的服务器应用程序从数据字符串中获取一个方法名称,查找它的地址并调用它,那么这就是一个明显的攻击向量。
在未全面检查是否明确允许该操作的情况下,切勿允许客户端数据查找服务器代码。
一些绝不能做的例子:
- 允许客户端在文本字段中向您发送 SQL
- 允许客户端向您发送 command-lines,您随后将其传递给
system()
、exec()
、spawn()
等... - 允许客户端向您发送共享库的名称和其中的函数名称...
等等。