启用 SYN Cookie 后,服务器不会为每个 SYN 包分配半连接队列条目,而是把关键握手信息编码进 SYN+ACK 的初始序列号,等收到合法 ACK 再还原连接,从而完全跳过半连接存储。
启用 SYN Cookie 后,服务器怎么跳过半连接队列
半连接队列在 TCP 三次握手里扮演的角色,有点像酒店前台登记本,正常模式下,每来一个 SYN,内核都要在队列里开一个格子,把客户端的 IP、端口、MSS、窗口规模等参数记下来,然后才回 SYN+ACK,攻击者只要狂发 SYN,这些格子很快被占满,正常用户的握手请求就被丢掉。
SYN Cookie 的思路完全不同,它不再给每个 SYN 开格子,而是现场算一段临时令牌,把状态压缩进 SYN+ACK 的序列号里,发完就直接忘记,等客户端回 ACK 时,服务器再根据 ACK 序列号校验令牌,还原出连接参数直接完成握手。
正常三次握手:半连接队列是每个 SYN 的登记本
正常流程中,服务器收到 SYN 后:
- 分配一个
request_sock结构,写入半连接队列 - 记录对端的 MSS、窗口规模因子、SACK 允许、时间戳等选项
- 发送 SYN+ACK,启动重传定时器
- 等待客户端返回 ACK,期间该条目一直占用内存
半连接队列长度受 tcp_max_syn_backlog 限制,攻击者只需伪造大量源 IP 发送 SYN,队列很快溢出。
SYN Cookie:把登记信息压进序列号,发完就忘
启用 SYN Cookie 后,收到 SYN 时:
- 内核不分配
request_sock,不写入半连接队列 - 以源 IP、目的 IP、源端口、目的端口、时间戳、MSS 等作为输入,计算出一个 cookie
- 把 cookie 作为 SYN+ACK 的初始序列号发回去
- 不再保存任何关于这个 SYN 的状态
- 客户端回 ACK 时,ACK 序列号等于 cookie+1
- 内核重新计算并校验 cookie,通过后直接创建完整的
sock放入 accept 队列 - 校验失败则静默丢弃
这一跳过的核心在于:状态不留在服务器内存,而是让网络包本身携带临时身份证明。
Linux syn cookie 原理:握手状态藏在序列号里
Linux 内核通过 net.ipv4.tcp_syncookies 控制 SYN Cookie,值 0 表示关闭,1 表示半连接队列满时触发,2 表示无条件开启,多数发行版默认值为 1。
Cookie 里到底藏了什么
SYN Cookie 不是一个简单随机数,它会根据连接四元组和当前时间计算哈希,并把 MSS 等少数参数编码进去。
- 源 IP、目的 IP、源端口、目的端口参与哈希,保证同一连接上下文一致
- 时间戳被编码进去,限制 cookie 有效期,防止重放
- MSS 被映射成少量索引位,只保留几个常用档位
- 窗口规模因子、SACK 允许等选项通常不会被编码,因为序列号长度有限
收到 ACK 时,内核从 ACK 序列号中取出 cookie 和时间戳,重新计算哈希比对,如果源 IP 被伪造,哈希对不上,直接丢弃,如果时间戳过期,同样丢弃。
syn cookie 和 syn queue 区别:一个记台账,一个发临时令牌
两者虽然都服务于三次握手,但工作逻辑完全不同,下表把关键差异展开:
| 对比项 | 半连接队列 syn queue | SYN Cookie |
|---|---|---|
| 状态存储位置 | 服务器内存中的 request_sock 结构 |
编码在 SYN+ACK 的序列号里 |
| 是否持续占用内存 | 每个 SYN 占用一条,直到 ACK 或超时 | 握手阶段不占半连接内存 |
| 能保存的 TCP 选项 | MSS、窗口缩放、SACK、时间戳等较完整 | 通常只保留 MSS 和时间戳 |
| 对抗 SYN flood 的能力 | 队列满后拒绝新连接 | 队列满后仍可完成合法握手 |
| 触发条件 | 默认工作模式 | 队列溢出或手动强制开启 |
| CPU 消耗 | 较低 | 每次 SYN 和 ACK 都需要哈希计算 |
| 连接建立后性能 | 选项完整,传输效率不受影响 | 窗口缩放和 SACK 可能缺失 |
| 适用场景 | 正常流量、低攻击风险 | 高并发、易受 SYN flood 攻击 |
简单说,半连接队列是长期台账,SYN Cookie 是临时通行证。
服务器防 syn flood 配置 syn cookie 的实操路径
在 Linux 服务器上配置 SYN Cookie 不复杂,但需要确认内核版本和当前策略。
查看内核开关状态
用以下命令查看当前值:
sysctl net.ipv4.tcp_syncookies
输出为 1 表示队列满时启用,2 表示强制启用,0 表示关闭。
还可以查看半连接队列溢出统计:
netstat -s | grep -i listen
如果出现 SYNs to LISTEN sockets dropped 或 TCPReqQFullDoCookies 计数增长,说明队列曾经被打满,Cookie 可能已经触发。
开启和持久化
临时开启:
sysctl -w net.ipv4.tcp_syncookies=1
永久写入 /etc/sysctl.conf 或 /etc/sysctl.d/99-sysctl.conf:
net.ipv4.tcp_syncookies = 1
执行以下命令使配置生效:
sysctl -p
若想无条件启用,可设置为 2:
sysctl -w net.ipv4.tcp_syncookies=2
同时可以调整半连接队列长度:
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
并降低 SYN+ACK 重传次数,加快队列回收:
sysctl -w net.ipv4.tcp_synack_retries=2
这些参数组合起来,能在攻击流量下给合法用户留出更多握手机会。
syn cookie 性能影响大吗?开启后连接慢的真相
SYN Cookie 不是免费午餐,它在握手阶段跳过了半连接存储,但也丢失了一部分 TCP 选项协商能力。
哪些环节会变慢
- 窗口缩放因子丢失:客户端和服务器无法协商大窗口,高带宽高延迟链路吞吐可能下降
- SACK 允许丢失:丢包后只能回退到累积确认,重传效率变低
- MSS 只能取少数档位:极端 MTU 场景下可能出现额外分片或小包
- 每次 ACK 都要做哈希校验:CPU 压力比正常握手略高
这些影响多数情况下只体现在连接建立后的传输阶段,三次握手本身并不会明显变慢。
什么场景不用太担心
内网、低延迟、小文件传输场景中,窗口缩放和 SACK 的作用有限,行业共识认为,面对 SYN flood 攻击,开启 SYN Cookie 是内核层性价比最高的兜底手段,正常连接优先使用半连接队列,只有队列溢出时才触发 Cookie,所以日常业务流量基本不受影响。
如果你在北京服务器租用环境部署高并发业务,建议先在测试环境开启 tcp_syncookies=1,用 iperf3 和真实业务包验证吞吐变化,多数情况下,防御收益会大于微小的性能损耗。
SYN Cookie 跳过的不是三次握手本身,而是半连接队列对内存的持续占用,它把状态从服务器内存搬到网络包的序列号里,用 CPU 哈希换内存安全,面对 SYN flood,这种无状态握手方式能让合法用户继续连接,而攻击者只能空耗自己的带宽。
Q&A:启用 SYN Cookie 后怎么跳过半连接存储?
Linux syn cookie 原理中 cookie 容易被伪造吗?
不容易,Cookie 计算包含源和目的 IP、端口、时间戳等,攻击者如果伪造源 IP,必须同时猜测哈希输入和当前时间窗口,由于时间戳会过期,即使截获了某个合法 cookie,也无法在过期后重复使用,伪造难度远高于直接消耗半连接队列。
服务器防 syn flood 配置 syn cookie 后,还需要调大半连接队列吗?
需要,SYN Cookie 是兜底,不是替代,正常连接仍优先使用半连接队列保存完整 TCP 选项,适当调大 tcp_max_syn_backlog 可以降低 Cookie 触发频率,减少选项丢失带来的传输效率下降,队列越大,正常用户越少被迫走 Cookie 路径。
北京服务器租用环境开启 syn cookie 会影响正常用户吗?
正常用户完成三次握手后,连接仍会建立,除非业务极度依赖大窗口和高吞吐,北京地域用户到服务器之间的延迟通常较低,窗口缩放丢失带来的影响相对有限,对于多数 Web、API、数据库代理类业务,正常用户几乎无感知,攻击流量却会被有效压制。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/636619.html





