文章目录
- [1.什么是 SYN Flood 攻击?](#1.什么是 SYN Flood 攻击?)
- 2.半连接与全连接队列
- [3.如何防范 SYN Flood 攻击?](#3.如何防范 SYN Flood 攻击?)
-
- 增大半连接队列
- [开启 SYN Cookie](#开启 SYN Cookie)
- [减少 SYN+ACK 重传次数](#减少 SYN+ACK 重传次数)
- 参考文献
1.什么是 SYN Flood 攻击?
SYN Flood 是互联网上最原始、最经典的 DDoS(Distributed Denial of Service)攻击之一。
SYN 报文指的是 TCP 协议中的 Synchronize 报文,是 TCP 三次握手过程中的首个报文。让我们先来了解一个正常的TCP三次握手过程。
TCP 连接建立需要三次握手,假设攻击者短时间伪造不同 IP 地址的 SYN 报文,服务端每接收到一个 SYN 报文,就进 SYN_RECV 状态,但服务端发送出去的 ACK + SYN 报文,无法得到未知 IP 主机的 ACK 应答,久而久之就会占满服务端的半连接队列,使得服务端不能为正常用户服务。
这就是 SYN Flood 攻击。
2.半连接与全连接队列
什么是 TCP 半连接和全连接队列?
TCP 三次握手时,Linux 内核会维护两个队列:
- 半连接队列,也称 SYN 队列。
- 全连接队列,也称 Accept 队列。
我们先来看下 Linux 内核的半连接队列与全连接队列是如何工作的?
- 当服务端接收到客户端的 SYN 报文时,会创建一个半连接的对象,然后将其加入到内核的「 SYN 队列」。
- 接着发送 SYN + ACK 给客户端,等待客户端回应 ACK 报文。
- 服务端接收到 ACK 报文后,从「 SYN 队列」取出一个半连接对象,然后创建一个新的连接对象放入到「 Accept 队列」。
- 应用通过调用 accpet() socket 接口,从「 Accept 队列」取出连接对象。
不管是半连接队列还是全连接队列,都有最大长度限制,超过限制时,默认情况都会丢弃报文。
SYN Flood 攻击方式最直接的表现就会把 TCP 半连接队列打满,这样当 TCP 半连接队列满了,后续再收到 SYN 报文就会丢弃,导致客户端无法和服务端建立连接。
3.如何防范 SYN Flood 攻击?
SYN Flood 的目的是占满服务器的连接数,消耗服务器的系统资源。对于服务器自身来说,最直接的做法就是提高服务能力,比如组建集群,升级硬件。但是这种方式成本巨大,且对于海量的攻击报文来说,并没有太大的作用,仅多撑几分钟甚至几秒而已。
防范 SYN Flood 攻击,可以有以下几种方法:
增大半连接队列
增大 TCP 半连接队列,要同时增大下面这三个参数:
增大 net.ipv4.tcp_max_syn_backlog
增大 listen() 函数中的 backlog
增大 net.core.somaxconn
开启 SYN Cookie
开启 SYN Cookie 功能就可以在不使用 SYN 半连接队列的情况下成功建立连接,相当于绕过了 SYN 半连接来建立连接。
- 当 「 SYN 队列」满之后,后续服务端收到 SYN 包,不会丢弃,而是根据算法,计算出一个 Cookie 值。Cookie 包含了一些与连接相关的信息,如初始序列号等,但不会在服务器端保存连接状态。
- 服务端将 Cookie 值放到第二次握手报文的「序列号」里回给客户端。
- 服务端接收到客户端的 ACK 报文时,通过将 ACK 报文减去 1 获取 Cookie,然后根据 Cookie 判断报文的合法性并重建连接状态,然后将该连接对象放入「 Accept 队列」。
- 最后应用程序通过调用 accpet() 函数,从「 Accept 队列」取出连接。
可以看到,当开启了 SYN Cookie 了,即使受到 SYN 攻击而导致 SYN 队列满时,也能保证正常的连接成功建立。
net.ipv4.tcp_syncookies 参数主要有以下三个值:
0 值,表示关闭该功能
1 值,表示仅当 SYN 半连接队列放不下时,再启用它
2 值,表示无条件开启功能
那么在应对 SYN 攻击时,只需要设置为 1 即可。
shell
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
减少 SYN+ACK 重传次数
当服务端受到 SYN 攻击时,就会有大量处于 SYN_RECV 状态的 TCP 连接,处于这个状态的 TCP 会重传 SYN+ACK ,当重传超过次数达到上限后,就会断开连接。
那么针对 SYN 攻击的场景,我们可以减少 SYN-ACK 的重传次数,以加快处于 SYN_REVC 状态的 TCP 连接断开。
SYN-ACK 报文的最大重传次数由 tcp_synack_retries内核参数决定(默认值是 5 次),比如将 tcp_synack_retries 减少到 2 次:
shell
echo 2 > /proc/sys/net/ipv4/tcp_synack_retries
参考文献
SYN 洪水DDoS 攻击 - Cloudflare
什么是SYN Flood?如何防御SYN Flood? - 华为
4.1 TCP 三次握手与四次挥手面试题 - 小林coding
TCP 半连接队列和全连接队列满了会发生什么?又该如何应对?
SYN cookies - wikipedia