Skip to main content

3. 协议详细说明 (Protocol Details)

本章详细说明 TCP Fast Open 的技术实现细节,包括选项格式、状态机转换和数据处理规则。

TCP 选项格式

+-------------+-------------+
| Kind=34 | Length=2 |
+-------------+-------------+

字段说明

  • Kind: 8 位,值为 34(TCP Fast Open 实验性选项编号)
  • Length: 8 位,值为 2(表示无 Cookie 数据,这是请求)

客户端行为规范

客户端请求 Cookie 时 MUST 遵循:

  1. 初始连接

    • 在 SYN 包的 TCP 选项中包含 Kind=34, Length=2
    • 不携带任何应用数据
    • 正常完成三次握手
  2. 选项放置

    • TFO 选项应放在其他 TCP 选项之后
    • 确保不超过 TCP 选项最大长度(40 字节)
  3. 重传处理

    • 如果 SYN 包需要重传,MUST 保留 TFO 选项
    • 重传计数应与标准 TCP 一致

服务器响应规范

服务器收到 Cookie 请求时 SHOULD

  1. Cookie 生成

    Input:  ClientIP, ServerSecret, Timestamp
    Output: Cookie = Encrypt(ServerSecret, ClientIP || Timestamp)
  2. 响应构造

    • 在 SYN-ACK 中包含 TFO Cookie 选项
    • Cookie 长度通常为 4 到 16 字节
    • 继续标准 TCP 握手流程
  3. 安全考虑

    • 定期轮换 ServerSecret(建议每几小时一次)
    • 实现 Cookie 过期机制
    • 监控异常请求模式

TCP 选项格式

+-------------+-------------+-------------------+
| Kind=34 | Length | Cookie (4-16字节) |
+-------------+-------------+-------------------+

字段说明

  • Kind: 8 位,值为 34
  • Length: 8 位,值为 6 到 18(2 + Cookie 长度)
  • Cookie: 4 到 16 字节的加密 Token

推荐的 Cookie 内部结构:

Cookie = AES-128(ServerSecret, ClientIP || Timestamp || Counter)

组成部分:
- ClientIP: 客户端 IP 地址 (4 或 16 字节)
- Timestamp: Unix 时间戳 (4 字节)
- Counter: 防重放计数器 (可选,4 字节)

服务器实现要点

MUST 实现

  • Cookie 必须绑定到客户端 IP 地址
  • Cookie 必须可验证(使用 MAC 或加密)
  • Cookie 必须有过期时间

SHOULD 实现

  • 使用加密强度高的算法(如 AES-128)
  • 实现密钥轮换机制
  • 记录 Cookie 使用统计

MAY 实现

  • Cookie 版本号(支持算法升级)
  • 额外的客户端信息(如端口号)
  • 速率限制信息

3.3. TCP Fast Open 连接 (Fast Open)

TCP 选项格式与数据

SYN 包结构:
+-------------+-------------+-------------------+
| Kind=34 | Length | Cookie (4-16字节) |
+-------------+-------------+-------------------+

TCP 段:
+------------------------+
| TCP Header |
+------------------------+
| TCP Options | (包含 TFO Cookie)
+------------------------+
| Application Data | (可选,最多 MSS)
+------------------------+

客户端发送规范

客户端使用 Fast Open 时 MUST

  1. Cookie 包含

    • 在 SYN 包的 TCP 选项中包含缓存的 Cookie
    • Cookie 必须是从目标服务器接收的有效 Cookie
  2. 数据携带

    • 可以 在 SYN 包中携带应用数据
    • 数据长度 MUST NOT 超过 MSS
    • 数据 MUST 是幂等的(可安全重传)
  3. 序列号

    • SYN 数据使用 ISN(初始序列号)
    • 数据序列号范围:[ISN+1, ISN+1+DataLen)
  4. 重传策略

    首次 SYN:包含 Cookie + Data
    ↓ (超时)
    重传 SYN:
    - 选项 1:重传 Cookie + Data(推荐)
    - 选项 2:仅重传 SYN,不带数据(保守)

服务器接收规范

服务器收到 Fast Open SYN 时的处理流程:

收到 SYN + TFO Cookie + Data

1. 验证 Cookie
├─ Cookie 格式检查
├─ IP 地址匹配检查
├─ 时间戳验证(是否过期)
└─ MAC/签名验证

2. Cookie 验证结果
├─ 有效 → 继续步骤 3
└─ 无效 → 丢弃数据,发送标准 SYN-ACK(不带数据响应)

3. 接受 SYN 数据
├─ 创建 TCB (Transmission Control Block)
├─ 状态:SYN-RECEIVED
├─ 将数据放入接收缓冲区
└─ 通知应用层有数据可读

4. 发送 SYN-ACK
├─ 确认 SYN 和数据(ACK = ISN + 1 + DataLen)
├─ 可选:在 SYN-ACK 中携带响应数据
└─ 可选:刷新 Cookie(返回新 Cookie)

5. 收到 ACK
└─ 连接进入 ESTABLISHED 状态

数据处理规则

SYN 数据的特殊性

  1. 幂等性要求

    • 客户端 MUST 确保 SYN 数据可以安全重传
    • 适合:HTTP GET 请求
    • 不适合:有副作用的操作(如 POST、DELETE)
  2. 应用层交付

    • 服务器 MAY 在 SYN-RECEIVED 状态交付数据给应用
    • 应用 SHOULD 在连接完全建立前谨慎处理数据
    • 服务器 SHOULD 限制 SYN-RECEIVED 状态的资源分配
  3. 数据重传

    场景:SYN 包丢失

    客户端:
    SYN + Cookie + Data (1st)
    ↓ (超时)
    SYN + Cookie + Data (2nd)

    服务器:可能收到重复数据
    → MUST 实现去重机制(通过序列号)

服务器端

# Cookie 生成伪代码
def generate_cookie(client_ip, server_secret, timestamp):
data = client_ip + timestamp
cookie = aes_encrypt(server_secret, data)
return cookie

def validate_cookie(cookie, client_ip, server_secret, max_age):
try:
data = aes_decrypt(server_secret, cookie)
stored_ip, timestamp = parse(data)

# 检查 IP 地址
if stored_ip != client_ip:
return False

# 检查过期时间
if current_time() - timestamp > max_age:
return False

return True
except:
return False

客户端端

# Cookie 缓存伪代码
class TFOCookieCache:
def __init__(self):
self.cookies = {} # {(server_ip, server_port): (cookie, timestamp)}

def store(self, server_ip, server_port, cookie):
key = (server_ip, server_port)
self.cookies[key] = (cookie, current_time())

def get(self, server_ip, server_port, max_age):
key = (server_ip, server_port)
if key in self.cookies:
cookie, timestamp = self.cookies[key]
if current_time() - timestamp < max_age:
return cookie
else:
del self.cookies[key] # 过期,删除
return None

主动更新

  • 服务器可以在任何 SYN-ACK 中返回新 Cookie
  • 客户端 SHOULD 使用最新收到的 Cookie

被动更新

  • Cookie 过期后,客户端重新请求
  • Cookie 验证失败后,客户端回退并请求新 Cookie

安全强化措施

防重放攻击

Cookie 中包含时间戳
→ 服务器拒绝过期 Cookie
→ 限制 Cookie 有效期(如 24 小时)

防 IP 欺骗

Cookie 绑定客户端 IP
→ 不同 IP 的客户端无法使用相同 Cookie
→ 移动网络场景需要考虑 IP 漂移

密钥管理

服务器密钥轮换
├─ 保持多个密钥活跃(当前 + 前一个)
├─ 定期生成新密钥(如每 8 小时)
└─ 旧密钥仅用于验证,不用于生成

故障处理

Cookie 验证失败处理

  1. 服务器行为

    • 发送标准 SYN-ACK(不确认 SYN 数据)
    • 可选:包含新的 Cookie 供后续使用
    • 继续标准 TCP 握手
  2. 客户端行为

    • 检测到 Fast Open 失败(数据未被确认)
    • 在 ACK 后重新发送应用数据
    • 清除失效的 Cookie
    • 可选:立即请求新 Cookie

网络中间设备干扰

某些防火墙或 NAT 可能:
- 剥离未知 TCP 选项
- 阻止带数据的 SYN 包
- 修改序列号

客户端应对策略:
- 实现回退机制
- 记录失败的服务器(避免重复尝试)
- 提供禁用 TFO 的选项

3.5. 状态机扩展 (State Machine Extensions)

客户端状态机

CLOSED
↓ (应用请求连接 + 有 Cookie)
SYN-SENT (发送 SYN + Cookie + Data)
↓ (收到 SYN-ACK,ACK 包括数据)
ESTABLISHED

[Fast Open 成功!]

OR

CLOSED
↓ (应用请求连接 + 无 Cookie)
SYN-SENT (发送 SYN,请求 Cookie)
↓ (收到 SYN-ACK + Cookie)
ESTABLISHED
↓ (缓存 Cookie)
[为下次连接准备]

服务器状态机

LISTEN
↓ (收到 SYN + 有效 Cookie + Data)
SYN-RECEIVED (接受数据,通知应用)
↓ (发送 SYN-ACK,确认数据)
↓ (收到 ACK)
ESTABLISHED

[Fast Open 成功!]

OR

LISTEN
↓ (收到 SYN + 无效/无 Cookie)
SYN-RECEIVED
↓ (发送 SYN-ACK,可能包含 Cookie)
↓ (收到 ACK)
ESTABLISHED

[标准 TCP 握手]

关键状态转换

SYN-RECEIVED 状态的特殊处理

  • 服务器 MAY 在此状态向应用层交付 SYN 数据
  • 应用 SHOULD 意识到连接尚未完全建立
  • 服务器 MUST 限制此状态的资源使用(防 DoS)

下一章节: 4. 安全考量 (Security Considerations) 将详细分析 TFO 的安全威胁和防护措施。