# SCTP association 与握手 · 四次握手和 Cookie

> 一个 SCTP association 是两端间的一条连接，建立它要四次握手——比 TCP 多一步，为的是用 Cookie 抵御 DoS 攻击。这一章讲清 association 是什么、四次握手 INIT/INIT-ACK/COOKIE-ECHO/COOKIE-ACK 的流程，以及 Cookie 机制的巧妙。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/webrtc/sctp-association
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# SCTP association 与握手 · 四次握手和 Cookie

一个 **SCTP association（关联）** 就是两端之间的一条 SCTP 连接（[类似 TCP 的 connection](https://daiw.org/manual/webrtc/data-channel-overview)），所有[数据通道复用它](https://daiw.org/manual/webrtc/sctp-streams)。用它之前得先**建立**——SCTP 的握手比 TCP 多一步，是**四次**，多出来的一步藏着精巧的安全设计。这一章看它。

## 四次握手

[`DcSctpSocket::Connect()`](https://daiw.org/manual/webrtc/dcsctp-intro) 发起握手。SCTP 用**四次**交换建立 association:

```mermaid
sequenceDiagram
    participant A as 发起方
    participant B as 接受方
    A->>B: ① INIT(我要连,这是我的参数)
    B->>A: ② INIT-ACK(好,这是我的参数 + 一个 Cookie)
    A->>B: ③ COOKIE-ECHO(把你的 Cookie 原样回给你)
    B->>A: ④ COOKIE-ACK(Cookie 对,连接建立!)
```

- **① INIT** —— 发起方说“我要建连”，附上初始参数（[TSN 起点](https://daiw.org/manual/webrtc/sctp-reliability)、[流数量](https://daiw.org/manual/webrtc/sctp-streams)、接收窗口等）。
- **② INIT-ACK** —— 接受方回应，附上**自己的参数**和一个 **Cookie**（下面详说）。
- **③ COOKIE-ECHO** —— 发起方把收到的 Cookie **原样送回**。
- **④ COOKIE-ACK** —— 接受方验证 Cookie 无误，association 建立，可以传数据了。

## 为什么多一步：Cookie 抗 DoS

TCP 三次握手就够了，SCTP 为什么要四次、多一个 Cookie 环节？

<Callout type="info">
  **那个多出来的 Cookie，是为了让接受方在握手完成前**不必分配任何状态**，从而抵御 DoS 攻击。** 想想 TCP 的 SYN Flood 攻击：攻击者狂发 SYN（第一步），服务器每收一个就**分配连接状态**（半开连接）等第三步——攻击者不回第三步，服务器的半开连接表被塞爆，资源耗尽。

  SCTP 的 Cookie 化解了它：收到 [INIT](https://daiw.org/manual/webrtc/sctp-association) 后，接受方**不分配任何状态**，而是把“建立这个连接所需的全部信息”打包、**签名**成一个 Cookie，塞进 INIT-ACK 发回去（**状态存在 Cookie 里，不在接受方内存里**）。只有当发起方[把 Cookie 原样送回（COOKIE-ECHO）](https://daiw.org/manual/webrtc/sctp-association)、且接受方验证签名无误时，才**真正分配状态**建立连接。于是攻击者狂发 INIT 也没用——接受方根本不为它们存状态，一身轻松。**“把状态外包给客户端（装进签名的 Cookie），验证通过才落地”**，是抗 DoS 的经典手法（和 [DTLS 的 HelloRetryRequest cookie](https://daiw.org/manual/webrtc/dtls-handshake)、[STUN 的无状态](https://daiw.org/manual/webrtc/stun-protocol)异曲同工）。多握一次手，换来了健壮——值。
</Callout>

## 握手协商了什么

四次握手不只是“建立连接”，还**协商**了这条 association 的关键参数：

- **初始 [TSN](https://daiw.org/manual/webrtc/sctp-reliability)** —— 数据块的起始序号（像 [TCP 的 ISN](https://daiw.org/manual/webrtc/rtp-packet)）。
- **[流的数量](https://daiw.org/manual/webrtc/sctp-streams)** —— 双方各支持多少条[入 / 出流](https://daiw.org/manual/webrtc/sctp-streams)。
- **接收窗口（a_rwnd）** —— [流控](https://daiw.org/manual/webrtc/sctp-flow-congestion)的初始窗口大小。
- **各种扩展能力** —— 比如支不支持[部分可靠（RFC 3758）](https://daiw.org/manual/webrtc/sctp-partial-reliability)。

协商完，双方就 association 的运作规则达成一致——和 [SDP 协商媒体](https://daiw.org/manual/webrtc/media-session)是一个道理，只是这里协商的是传输层参数。在 WebRTC 里，SCTP 跑在[已经建好的 DTLS 上](https://daiw.org/manual/webrtc/data-channel-overview)，所以这四次握手是在[加密通道内](https://daiw.org/manual/webrtc/srtp-encryption)进行的——又快又安全。

## 小结与下一章

一个 **SCTP association** 是两端间的连接，[数据通道复用它](https://daiw.org/manual/webrtc/sctp-streams)。[`Connect()`](https://daiw.org/manual/webrtc/dcsctp-intro) 发起**四次握手**：**INIT → INIT-ACK（带 Cookie）→ COOKIE-ECHO → COOKIE-ACK**。比 TCP 多的那步用 **Cookie 抗 DoS**——接受方握手完成前**不分配状态**（状态签名进 Cookie 外包给客户端），验证回传的 Cookie 才落地，免疫 SYN-Flood 式攻击。握手还[协商 TSN / 流数 / 窗口 / 扩展](https://daiw.org/manual/webrtc/sctp-reliability)。它跑在[已建的 DTLS](https://daiw.org/manual/webrtc/data-channel-overview) 内。

握手建好了连接，数据怎么组织？SCTP 的数据单位是“chunk”，装进“packet”。下一章看包和块的结构。👉 [SCTP 包与 chunk](https://daiw.org/manual/webrtc/sctp-chunks-packets)。

## 参考资料

- [1] libwebrtc 源码.`net/dcsctp/socket/`（握手状态机）、`net/dcsctp/packet/chunk/`（INIT/COOKIE 等 chunk）。
- [2] IETF RFC 9260「SCTP」§ 4-5（association 建立、Cookie 机制）。
- [3] 关联[DTLS 握手](https://daiw.org/manual/webrtc/dtls-handshake)、[STUN 无状态](https://daiw.org/manual/webrtc/stun-protocol)——抗 DoS 的类似思路。
