Skip to main content

5.6 序列号负载 (Sequence Number Payload)

序列号(SEQ)负载用于提供重放攻击保护。它在GROUPKEY-PULL响应和GROUPKEY-PUSH消息中使用。

SEQ负载格式

 0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload ! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Sequence Number !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

字段说明:

  • Next Payload: 下一个负载的类型
  • Payload Length: 固定为8字节
  • Sequence Number: 32位序列号

序列号的使用

在GROUPKEY-PULL中

GCKS可以 (MAY) 在GROUPKEY-PULL响应中包含SEQ负载:

HDR*, HASH(2), SA, [KE,] [NONCE,] [SEQ]

SEQ负载的值:

  • 初始值: GCKS为该群组当前使用的序列号
  • 用途: 告知组成员下一个GROUPKEY-PUSH消息将使用的序列号范围

在GROUPKEY-PUSH中

GCKS必须 (MUST) 在每个GROUPKEY-PUSH消息中包含SEQ负载:

HDR*, SEQ, [SA,] [KD,] [POP,] [D]

SEQ负载的值:

  • 递增: 每个新的GROUPKEY-PUSH消息的序列号必须 (MUST) 大于前一个
  • 唯一性: 每个GROUPKEY-PUSH消息有唯一的序列号

序列号的初始化

GCKS在开始向群组发送GROUPKEY-PUSH消息时:

  1. 选择初始值: 选择一个初始序列号(可以是0或随机值)
  2. 通知成员: 通过GROUPKEY-PULL响应中的SEQ负载告知成员
  3. 递增: 每发送一个GROUPKEY-PUSH消息,序列号加1

重放检测

组成员的处理

组成员必须 (MUST) 实现重放检测:

  1. 记录序列号: 记录最后接收和处理的GROUPKEY-PUSH消息的序列号
  2. 比较序列号: 接收新消息时,比较其序列号与记录的值
  3. 拒绝旧消息: 如果新消息的序列号小于或等于记录的值,拒绝该消息
  4. 处理新消息: 如果新消息的序列号更大,处理该消息并更新记录的序列号

处理序列号间隙

如果组成员检测到序列号间隙(如从5跳到8):

  • 可能原因: 数据包丢失或乱序
  • 处理方式:
    • 继续处理序列号更大的消息
    • 可以 (MAY) 请求GCKS重传丢失的消息(如果协议支持)
    • 可以 (MAY) 执行新的GROUPKEY-PULL以获取最新状态

序列号回绕

序列号是32位的,最终会回绕:

  • 回绕检测: 实现应该 (SHOULD) 检测序列号回绕
  • 处理方式: 当序列号从大值跳到小值时,如果跳跃足够大(如从0xFFFFFFFF到0x00000001),视为回绕而非重放
  • 重新初始化: GCKS可以 (MAY) 在回绕时重新初始化群组

与ISAKMP消息ID的关系

SEQ负载与ISAKMP头中的消息ID(Message ID)协同工作:

  • 消息ID: GCKS为每个GROUPKEY-PUSH生成唯一的消息ID
  • SEQ负载: 提供额外的序列保证
  • 双重保护: 两者结合提供更强的重放保护

处理规则

GCKS规则

GCKS必须 (MUST):

  1. 初始化序列号: 为每个群组维护一个序列号计数器
  2. 递增序列号: 每发送一个GROUPKEY-PUSH消息时递增序列号
  3. 包含SEQ负载: 在每个GROUPKEY-PUSH消息中包含SEQ负载
  4. 持久化: 将序列号持久化存储以防止重启后重用
  5. 通知初始值: 在GROUPKEY-PULL响应中可选地通知初始序列号

组成员规则

组成员必须 (MUST):

  1. 初始化状态: 从GROUPKEY-PULL响应中的SEQ负载(如果有)初始化期望的序列号
  2. 验证序列号: 对每个接收的GROUPKEY-PUSH消息验证序列号
  3. 拒绝重放: 拒绝序列号小于或等于已处理消息的消息
  4. 更新状态: 成功处理消息后更新记录的序列号
  5. 处理间隙: 正确处理序列号间隙和回绕

安全考虑

序列号提供重放攻击保护:

  • 防止重放: 防止攻击者重放旧的GROUPKEY-PUSH消息
  • 必需保护: SEQ负载必须 (MUST) 受到完整性保护(通过KEK)
  • 不可预测: 初始序列号可以 (MAY) 使用随机值以增加安全性
  • 持久化: GCKS必须 (MUST) 确保重启后不重用序列号

没有序列号保护,攻击者可以:

  • 重放旧的GROUPKEY-PUSH消息
  • 导致组成员使用过期的密钥
  • 破坏群组的前向访问控制

因此,正确实现序列号机制对GDOI的安全性至关重要。

示例

示例1: 正常操作

GCKS发送:
GROUPKEY-PUSH #1, SEQ = 100
GROUPKEY-PUSH #2, SEQ = 101
GROUPKEY-PUSH #3, SEQ = 102

组成员接收:
接收SEQ=100, 接受(首次)
接收SEQ=101, 接受(101 > 100)
接收SEQ=102, 接受(102 > 101)

示例2: 重放攻击

GCKS发送:
GROUPKEY-PUSH #1, SEQ = 100
GROUPKEY-PUSH #2, SEQ = 101

攻击者重放:
重放GROUPKEY-PUSH #1, SEQ = 100

组成员处理:
接收SEQ=100, 接受(首次)
接收SEQ=101, 接受(101 > 100)
接收SEQ=100, 拒绝(100 <= 101, 重放攻击)

示例3: 数据包丢失

GCKS发送:
GROUPKEY-PUSH #1, SEQ = 100
GROUPKEY-PUSH #2, SEQ = 101 (丢失)
GROUPKEY-PUSH #3, SEQ = 102

组成员接收:
接收SEQ=100, 接受
接收SEQ=102, 接受(检测到间隙,但继续处理)
(可选)请求重传SEQ=101