TCP 3(三次握手中的问题)

张开发
2026/4/11 10:14:37 15 分钟阅读

分享文章

TCP 3(三次握手中的问题)
第一次握手丢失了会发生什么当 TCP 三次握手的第一次握手即客户端发送的 SYN 报文丢失时会触发客户端的超时重传机制。客户端行为启动定时器客户端发送 SYN 报文后会进入SYN_SENT状态并启动一个重传定时器。超时重传如果在设定的时间RTO, Retransmission Timeout内没有收到服务端的 SYNACK 响应客户端会认为 SYN 报文已丢失并重新发送 SYN 报文。指数退避为了应对网络拥塞重传的等待时间会采用“指数退避”算法即每次等待的时间都会翻倍。在 Linux 系统中初始 RTO 通常为 1 秒后续的重传间隔依次为 2 秒、4 秒、8 秒等。放弃连接重传次数并非无限。它受到内核参数tcp_syn_retries的限制默认值通常为 5 次。如果达到最大重传次数后依然没有收到服务端的响应客户端就会放弃连接并向应用程序返回一个“连接超时”的错误。服务端行为在整个过程中由于服务端从未收到客户端的 SYN 报文所以它完全感知不到这次连接请求的存在。服务端会一直保持在LISTEN状态等待新的连接请求。第二次握手丢失了会发生什么当 TCP 三次握手的第二次握手即服务端发送的 SYNACK 报文丢失时会同时触发客户端和服务端双方的超时重传机制因为双方都处于等待对方响应的状态。客户端行为等待确认客户端在发出第一次握手SYN后会进入SYN_SENT状态等待服务端的 SYNACK 报文。误判并重传由于迟迟收不到服务端的 SYNACK客户端会误以为是自己发出的第一次握手SYN报文丢失了。触发重传因此客户端会触发超时重传机制再次发送 SYN 报文。这个重传行为与“第一次握手丢失”时客户端的行为完全一样同样受tcp_syn_retries参数控制。服务端行为等待确认服务端在成功接收客户端的 SYN 报文后会进入SYN_RCVD状态并向客户端发送 SYNACK 报文。触发重传由于第二次握手SYNACK在网络中丢失服务端迟迟收不到客户端的第三次握手ACK确认。因此服务端会认为自己的 SYNACK 报文丢失了。重传 SYNACK服务端会触发自己的超时重传机制重新发送 SYNACK 报文。这个重传次数由 Linux 内核参数tcp_synack_retries控制默认值通常为 5。最终结果连接成功只要客户端或服务端任意一方的重传报文成功到达对方后续的握手流程就能正常进行连接最终可以建立。连接失败如果网络状况极差导致双方的重传报文都持续丢失那么客户端和服务端都会在达到各自的最大重传次数后放弃连接并释放资源。第三次握手丢失了会发生什么当 TCP 三次握手的第三次握手即客户端发送的 ACK 报文丢失时情况与前两次握手丢失有所不同因为此时客户端已经认为连接建立成功。服务端行为等待确认服务端在发送了第二次握手SYNACK后会进入SYN_RCVD状态等待客户端的 ACK 确认。触发重传由于 ACK 报文丢失服务端在超时时间内未收到确认会认为自己的 SYNACK 报文丢失了。重传 SYNACK服务端会触发超时重传机制重新发送 SYNACK 报文。这个重传次数由 Linux 内核参数tcp_synack_retries控制默认值通常为 5 次。如果达到最大重传次数后仍未收到 ACK服务端将放弃连接并释放资源。客户端行为客户端在发出第三次握手ACK后其 TCP 连接状态会立即变为ESTABLISHED已建立。这意味着客户端认为连接已经成功可以开始发送数据了。接下来会发生什么取决于客户端是否立即发送数据。场景一客户端不立即发送数据如果客户端在连接建立后没有立即发送数据它会收到服务端重传的 SYNACK 报文。客户端在收到这个重复的报文后会再次发送一个 ACK 报文作为确认从而帮助服务端完成连接的建立。场景二客户端立即发送数据客户端在发出 ACK 后如果立刻向服务端发送数据会发生以下情况数据携带确认TCP 协议规定数据报文同样可以将 ACK 标志位置为 1。因此客户端发送的第一个数据包本身就起到了确认的作用。服务端完成握手当服务端收到这个数据包时它会识别出其中的 ACK 标志从而确认第三次握手已经完成。服务端会立即从SYN_RCVD状态转变为ESTABLISHED状态并将该连接从半连接队列移入全连接队列然后正常处理客户端发来的数据。一个常见的误区是认为服务端会因为没收到纯 ACK 包而回复一个 RST重置报文来断开连接。实际上只有在服务端已经放弃该连接例如重传次数耗尽后的情况下再收到客户端的数据才会回复 RST 报文。最终结果连接成功在绝大多数情况下通过服务端的 SYNACK 重传机制或者客户端立即发送的数据包第三次握手的确认都能成功送达服务端连接最终可以正常建立。连接失败只有在网络状况极差导致服务端的所有 SYNACK 重传和客户端的所有数据包都丢失服务端才会在达到最大重传次数后放弃连接。什么是 SYN 攻击如何避免 SYN 攻击SYN 攻击也称为 SYN 泛洪SYN Flood攻击是一种非常常见的拒绝服务DoS攻击。它通过利用 TCP 协议三次握手的固有缺陷耗尽目标服务器的资源使其无法为正常用户提供服务。什么是 SYN 攻击SYN 攻击的原理基于 TCP 三次握手过程正常握手客户端发送一个 SYN 包请求连接 → 服务器回复 SYNACK 包并分配资源进入SYN_RECV状态 → 客户端回复 ACK 包连接建立。攻击过程攻击者会伪造大量的虚假 IP 地址并向服务器持续发送海量的 SYN 请求包。资源耗尽服务器为每一个收到的 SYN 请求都会分配内存资源并发送 SYNACK 包进行响应然后进入SYN_RECV状态等待客户端的 ACK 确认。由于源 IP 是虚假的服务器永远收不到 ACK 回复这些未完成的连接称为“半连接”会一直占用服务器资源直到超时。服务瘫痪当服务器的“半连接队列”被这些虚假连接占满后它就无法再处理任何新的、来自真实用户的连接请求从而导致服务中断或系统瘫痪。如何避免 SYN 攻击防御 SYN 攻击需要采取多层次、纵深化的策略从操作系统内核到网络边界设备协同工作。1. 操作系统层优化这是在服务器本机进行的第一道防线主要通过调整内核参数来增强自身的抵抗能力。启用 SYN Cookies这是防御 SYN 攻击最核心、最有效的手段之一。它的原理是服务器在收到 SYN 请求后不立即分配内存资源来保存连接状态而是根据连接信息源/目的 IP、端口、时间戳等通过哈希算法计算出一个“Cookie”值并将其作为初始序列号放入 SYNACK 包中发送出去。只有当收到带有正确 ACK 值的回复时服务器才会验证 Cookie 并分配资源建立连接。这从根本上避免了半连接队列被耗尽的风险。Linux 启用命令echo 1 /proc/sys/net/ipv4/tcp_syncookies调整内核参数扩大半连接队列增加tcp_max_syn_backlog的值让服务器能容纳更多的半连接提高应对突发流量的能力。缩短超时时间减少tcp_synack_retries的值让服务器更快地放弃无效的半连接从而释放资源。2. 网络设备层防护在网络入口处部署防火墙或专业的 Anti-DDoS 设备可以在攻击流量到达服务器之前就进行识别和过滤。SYN Proxy (代理)防火墙设备会代替后端服务器与客户端完成 TCP 三次握手。只有当握手成功确认为真实连接后防火墙才会与后端服务器建立新的连接。这样所有的虚假 SYN 请求都在网络边界被拦截。源认证与首包丢弃源认证Anti-DDoS 设备拦截 SYN 包代替服务器回复 SYNACK。如果客户端能正确回复 ACK则被认为是真实源其后续流量会被放行。首包丢弃设备会直接丢弃收到的第一个 SYN 包。由于正常的 TCP 客户端在超时后会重传 SYN 包而攻击者通常使用海量伪造源 IP不会重传。设备只对重传的 SYN 包进行源认证这大大减轻了设备自身的处理压力。速率限制配置防火墙规则限制单位时间内来自同一 IP 地址或发往同一端口的 SYN 包数量超过阈值的包将被直接丢弃。3. 架构与服务层防护对于大规模或复杂的攻击单点防御可能不够需要从整体架构和外部服务入手。使用 CDN 或 DDoS 防护服务将业务流量接入专业的 DDoS 防护服务如 Cloudflare、阿里云 DDoS 防护等。这些服务拥有巨大的带宽资源和先进的清洗中心能够将恶意攻击流量从正常流量中分离出来只将“干净”的流量回源到你的服务器。构建多层防御体系最有效的防护是结合以上所有手段。例如在服务器上启用 SYN Cookies 作为最后一道防线在网络边界使用防火墙进行 SYN Proxy 和速率限制并接入云服务商的 DDoS 防护服务来抵御超大流量的攻击。

更多文章