【问题标题】:Message delimitation in TCP communicationTCP通信中的消息定界
【发布时间】:2015-08-15 18:34:45
【问题描述】:

我是网络新手,尤其是 TCP(我一直在用 UDP 愚弄一下,但仅此而已)。 我正在开发一个基于在两个端点之间交换消息的简单协议。这些消息需要经过认证,所以我实现了一个加密层来处理这个问题。然而,虽然 UDP 对构成一次可以传输的最小单元的数据包有一个合理的定义,但 TCP 协议(​​据我的理解)是完全面向流的。

现在,这让我有点困惑。交换消息时,我如何知道一个从哪里开始,另一个在哪里结束?原则上,我显然可以传达固定长度的消息,或者首先在某个标头中传达每条消息的大小。然而,这可能会受到攻击:虽然不可能扭曲或确定通信的内容,但上述技术只需在中间添加一个字节就可以很容易地完全破坏我的通信。

假设我需要传输一条 1234567 字节长的消息。首先,我用一个表示消息大小的整数传递 4 个字节。好的。然后我开始发送实际消息。该消息被分成几个数据包,分别接收。现在,攻击者只是发送一个额外的数据包,假装它是对话的一部分。它可以只有一个字节长:这完全破坏了我实现的任何同步机制!消息中间有一个虚假字节,它没有成功解码。不仅如此,第一条消息的最后一个字节破坏了第二条消息的对齐方式,依此类推:连接被破坏,而且攻击很简单!无论如何,这种攻击的可能性和可行性有多大?

所以我想知道:一次可以传输的最大数据单元是多少?我知道发送调用与接收调用不对应:消息可以分成不同的块。如何以某种方式将数据包组合在一起,以便我知道它们被打包在一起?有没有办法定义一个更高级别的消息,该消息被重新构建和对齐并触发对类似接收函数的单个调用?如果没有,我还能找到哪些其他解决方案来让我的通信即使在攻击者面前也能重新对齐?

【问题讨论】:

  • ietf.org/rfc/rfc2385.txt 与您描述的内容非常相关。 (并且一些操作系统支持 TCP-MD5 签名,通常通过调用 setsockopt() 来启用)
  • 1) TCP 有序列号;你不能注入几个字节到流中而不会使通信混乱。 2)没有消息边界;您必须在应用程序级协议中实现自己的边界,或者通过使用固定长度的消息,或者通过在 messages 前加上标头(期望什么)或通过 messages 来分隔它们i>消息结束字符,例如\n
  • @wildplasser 实际上,您可能可以将几个字节注入流中,因为活跃的 MITM 攻击者也可以修改 SEQ/ACK。对于某些网络堆栈,由于它们对out-of-band data 的(错误)处理,它甚至更容易。

标签: sockets security tcp


【解决方案1】:

基本上很难控制操作系统将流分成 TCP 数据包的方式(定义 TCP 协议的 RFC 规定 TCP 堆栈应该允许客户端通过使用 push 函数来强制它发送缓冲数据,但它没有定义应该生成多少数据包。毕竟攻击者可以修改其中任何一个)。

这些 TCP 数据包在通过网络的过程中可能会被更多地划分为 IP 片段(可以通过“不分段”IP 标志来选择退出 - 但这个标志可能会导致您的数据包无法传递完全)。

我认为您的问题不在于将数据包引入流协议,而在于保护它

IPSec 在您的场景中可能非常有用,因为它在网络层上运行。

它为发送的每个数据包提供完整性,因此可以检测到任何在线修改并丢弃无效数据包。在 TCP 的情况下,丢弃的数据包会自动重新传输。

(几乎)一切都是由操作系统自动完成的——所以你不必担心(这样做会犯错误)。

也可以确保机密性(具有不重复发明轮子的相同优势)。

IPSec 应该为您提供可靠的传输协议,您可以在该协议之上使用您喜欢的任何帧格式。

另一种选择是在 TCP 会话之上使用 SSL/TLS,这不太可靠(因为它确实会在完整性错误时关闭整个连接)。

【讨论】:

  • “基本上很难控制操作系统将流划分为 TCP 数据包的方式”。是不可能的。 TCP 有权以它喜欢的任何方式这样做。它是一种字节流协议。实现“推送”功能的 PSH 标志适用于当前段及其之前的所有内容。没有什么不确定的。无论如何,它已经过时了。
  • @EJP 绝对可以控制它(即嵌入式系统,原始套接字),但很难:)
  • @EJP 和 push 函数 没有定义 如何 堆栈将流分成数据包(这意味着未定义)。
  • 当然,操作系统可以控制它。如果您不是操作系统,则不会。我们讨论的是 TCP,而不是原始套接字。 '推送函数没有定义堆栈如何将流分成数据包'这句话基本上没有意义。 “推送功能”一个单比特标志,它已经一个段内。
  • @EJP 声明 TCP 堆栈应该允许客户端使用推送功能强制它发送缓冲数据的意思是,客户端应该能够强制 TCP 堆栈发送数据(在发送端作为输出缓冲可能正在发生)。参见here(以“有时用户需要确保他们提交给TCP的所有数据都已传输”开头的段落)。通常这发生在flush()
【解决方案2】:

现在,攻击者只是发送一个额外的数据包,假装它是对话的一部分。它可以只有一个字节长:这完全破坏了我实现的任何同步机制!

通过保护流来解决此类注入问题。创建一个加密流并通过它发送您的数据包。

当然加密流本身就有这个问题;它的消息可能已损坏。但是这些消息具有安全的完整性检查。检测到问题,可以断开连接并重新建立以重新同步。

此外,一些固定长度的同步/成帧位序列可以在消息之间使用:一些特定的位模式。该模式是否偶然出现在消息中并不重要,因为我们只会在出现问题(收到损坏的消息)时专门寻找该模式,否则我们会跳过该序列。如果收到损坏的消息,我们将接收字节,直到我们看到同步模式,并假设它后面的任何内容都是消息的开始(长度后跟有效负载)。如果 that 失败,我们重复这个过程。当我们收到正确的消息时,我们会回复对等点,它会重新传输我们没有收到的任何内容。

这种攻击的可能性和可行性有多大?

TCP 连接由四项标识:源和目标 IP,以及源和目标端口号。攻击者必须伪造一个与这四个标识符中的流匹配的数据包,然后将该数据包偷偷通过该攻击者和接收机器之间的所有路由器和防火墙。攻击者还必须在 TCP 序列号方面处于正确的位置。

基本上,攻击者 C 几乎不可能对网络上远离 C 的端点 A 和 B 实施攻击。在 C 能够到达其目的地之前很久,虚假的源 IP 就会被拒绝。作为内部工作(包括恶意软件)更合理:C 接近 A 和 B。

【讨论】:

    猜你喜欢
    • 2014-07-25
    • 2014-09-20
    • 2015-03-31
    • 2019-05-06
    • 2014-10-11
    • 1970-01-01
    • 1970-01-01
    • 2016-08-21
    • 1970-01-01
    相关资源
    最近更新 更多