TCP/IP能否防止数据包重放攻击?

3
TCP/IP是否防止多个相同数据包到达目的地?或者需要端点在其上层添加幂等逻辑?
如有可能,请引用TCP/IP规范中的具体段落。

嗯,这看起来像大学考试问题... - Pablo Fernandez
不,我想知道是否需要在我的应用层添加额外的逻辑来防止重放攻击。 - Gili
8个回答

9
TCP协议栈的工作是从重复的数据包中恢复:

TCP必须从因互联网通信系统而受损、丢失、重复或无序传递的数据中恢复。这通过为每个传输的八位字节分配一个序列号并要求接收TCP发出肯定确认(ACK)来实现。如果在超时时间内未收到ACK,则重新传输数据。在接收端,序列号用于正确排序可能乱序接收的段并消除重复。通过向每个传输的段添加校验和、在接收端进行检查并丢弃受损的段来处理受损。

-- RFC 793 - 传输控制协议,1.5部分

然而,如果它们是带有新序列号的相同数据包,则不会恢复。


你的回答中有一部分说端点必须从重复的数据包中恢复,而另一部分则说TCP必须从重复的数据包中恢复。这两者不是相互矛盾吗?也许你的意思是端点的工作是从重复的请求中恢复?请编辑你的回答。 - Gili
TCP协议栈的工作是处理重复数据包。这就是为什么数据包有一个序列号,以便您可以确定哪些是来自同一请求的。但是,没有任何防止设备使用不同的序列号发送“重复”数据包的措施。 - Powerlord
对,这就是为什么我写的回复应该可能应该读作:“重复请求(而不是数据包)的恢复是TCP协议栈的工作:” - Gili

6
TCP使用序列号来检测重传中的重复,这也将防止琐碎的重放攻击。
来自RFC 793,第3.3节 - 序列号:
设计中的一个基本概念是TCP连接中发送的每个数据八位字节都有一个序列号。由于每个八位字节都被排序,因此可以对每个八位字节进行确认。采用的确认机制是累积的,因此序列号X的确认表示已接收到但不包括X的所有八位字节。该机制允许在重传存在的情况下直接检测重复。片段内八位字节的编号是指头部后立即跟随的第一个数据八位字节是最低编号的,其后的八位字节顺序编号。
重复检测将确保同一数据包不能轻易地被重新传输。序列号还将确保在数据流中插入(而不是替换)的数据会引起注意,因为跟随伪造数据包的进一步合法数据包将具有重复的序列号,这将破坏数据流。这可能导致这些数据包被丢弃为重复项,从而可能会破坏正在使用的协议。

关于原始的(1981年)TCP/IP规范的更多信息可以在RFC 793中找到,以及涉及TCP/IP协议扩展或修改的许多其他RFC。


4

是的,TCP层可以防止重复的数据包。它下面的IP层则不能。

详见RFC 1122


3

您好,您似乎关心两个不同的问题:

  1. TCP可靠传输提供了什么保证
  2. 攻击者能否通过重放攻击影响我的服务器进程

回答1:

TCP保证字节序列的可靠有序传递。客户端应用程序通过write()发送的任何数据将在服务器的read()调用期间完全相同。

回答2:

重放攻击对TCP不起作用,因为每个连接都依赖于由客户端和服务器分别生成的两个随机32位数字。要使重放攻击起作用,攻击者必须猜测服务器为其正在发起的假连接生成的序列号(理论上,攻击者有1/2 ** 32的机会猜对)。如果攻击者猜错,她最多只会导致操作系统中的一些数据缓冲。

请注意,仅因为重放攻击无法起作用,并不意味着没有任何防止攻击者与您的服务器建立合法连接并向您的应用程序传输任何数据流的措施。这就是为什么始终重要的原因是验证输入


2

TCP以下的层可能会遇到多个数据包或丢失数据包的情况。而TCP以上的层则不会遇到重复或丢失数据包的问题。


1

我不知道数据包重复的情况,但是在使用TCP/IP时我从未遇到过这种情况。我知道TCP/IP可以保证所有数据包都能按正确顺序到达,所以我无法理解为什么会出现这种情况。


1

这真的取决于你如何接收数据 - 尽管技术上协议不应该给你重复的数据包(即具有相同TCP校验和的数据包),但其他因素可能会导致你看到重复的数据包 - 例如,你使用的网络硬件;此外,如果你使用嗅探器来查看TCP流,而不仅仅是在应用程序中读取一个打开的套接字,即使嗅探器实际监视的TCP流没有重复的数据包,也有可能从嗅探器中获得重复的数据包。

举个现实世界的例子 - 目前我正在为一家主要股票交易所分析内部网络的TCP数据,并且我正在从多个嗅探器中获取数据并将其拼接回来。因此,在拉取数据时,我发现需要进行许多预处理步骤,包括查找和删除重复项。例如,在我刚刚读取的流中,大约有60,000个数据包,我已经找到并删除了95个重复的数据包。

我采取的策略是保持最近10个TCP校验和的滚动窗口,并忽略与这些校验和匹配的数据包。请注意,这对PSH数据包很有效,但对ACK数据包效果不佳 - 但我对这些数据包不太关心。

我编写了一个特殊的集合,用于跟踪这个滚动窗口的TCP校验和,这可能对其他人有所帮助:

/// <summary>
/// Combination of a double-linked-list and a hashset with a max bound; 
/// Works like a bounded queue where new incoming items force old items to be dequeued; 
/// Re-uses item containers to avoid GC'ing;
/// Public Add() and Contains() methods are fully thread safe through a ReaderWriterLockSlim;
/// </summary>
public class BoundedHashQueue<T>
{
    private readonly int _maxSize = 100;
    private readonly HashSet<T> _hashSet = new HashSet<T>();
    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    private readonly Item _head;
    private readonly Item _tail;
    private int _currentCount = 0;

    public BoundedHashQueue(int maxSize)
    {
        _maxSize = maxSize;
        _head = _tail = new Item();
    }

    private class Item
    {
        internal T Value;
        internal Item Next;
        internal Item Previous;
    }

    public void Add(T value)
    {
        _lock.Write(() =>
            {
                if (_currentCount == 0)
                {
                    Item item = new Item();
                    item.Value = value;
                    _head.Next = item;
                    item.Previous = _head;
                    item.Next = _tail;
                    _tail.Previous = item;
                    _currentCount++;
                }
                else
                {
                    Item item;
                    if (_currentCount >= _maxSize)
                    {
                        item = _tail.Previous;
                        _tail.Previous = item.Previous;
                        _tail.Previous.Next = _tail;
                        _hashSet.Remove(item.Value);
                    }
                    else
                    {
                        item = new Item();
                        _currentCount++;
                    }
                    item.Value = value;
                    item.Next = _head.Next;
                    item.Next.Previous = item;
                    item.Previous = _head;
                    _head.Next = item;
                    _hashSet.Add(value);
                }
            });
    }

    public bool Contains(T value)
    {
        return _lock.Read(() => _hashSet.Contains(value));
    }
}}

0

你没有完全理解这个问题。 请查看此链接: http://en.wikipedia.org/wiki/Transmission_Control_Protocol

在这个页面上写着:

“TCP时间戳,定义在RFC 1323中,帮助TCP计算发送方和接收方之间的往返时间。时间戳选项包括4字节的时间戳值,其中发送方插入其时间戳时钟的当前值,以及4字节的回显回复时间戳值,其中接收方通常插入其已接收到的最近时间戳值。发送方使用回显回复时间戳来确认自己发送的段自发送以来经过的总时间[2]。

TCP时间戳也用于帮助处理TCP序列号遇到它们的2^32边界并“环绕”序列号空间的情况。这个方案被称为保护包装序列号或PAWS(详见RFC 1323)。”

问候, Joint(波兰)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接