【翻译】ietf-quic-draft-24: 8. Address Validation

英文原文链接:8. Address Validation

  地址有效性被 QUIC 用于防止流量放大攻击。在这种攻击下,攻击者使用受害者的地址作为包的源地
址并发送给服务端。如果服务端生成更多或者更大的包作为攻击包的响应,攻击者则可以利用服务端向受
害者发送更多的数据,这些数据量比攻击者发送的数据量要大。
  放大攻击的主要防御手段就是验证能接收包的端点的传输层地址的有效性。地址有效性验证是在连接
建立阶段(详见 8.1 小节)或连接迁移阶段(详见 8.2 小节)完成的,

8.1. Address Validation During Connection Establishment

  连接的建立隐式地为两端提供了地址有效性验证,接收到一个用握手的密钥保护的包意味着客户单接收
到了从服务端发送的 Initial 包。一旦服务端成功处理了一个客户端发送的 Handshake 包,那么它
可以认为客户端的地址已经被验证为有效。
  在验证客户端的地址有效之前,服务端不可以发送超过它接受到的数据的三倍大小的数据;这限制了
任何通过伪造源地址进行放大攻击的攻击强度;在确定这个限制值时,服务端只需要计算已经成功处理
的包的总大小。

  客户端必须保证包含 Initial 包的 UDP 报文至少有 1200 字节的载荷,可通过填充来达到该大
小。客户端发送填充的报文可以确保服务端不会过度受到放大限制的约束。
  包丢失,尤其是服务端的 Handshake 包丢失,会造成服务端无法发送数据,假设此时服务端还没
达到发送上限且客户端也没有数据发送;为了避免造成握手死锁发生,客户端应该在探测超时时发送一个
包,如 [QUIC-RECOVERY] 所述。如果客户端没有重传数据并且也没有 Handshake 密钥,它应该发送
一个包含 Initial 包的 UDP 报文,报文载荷至少为 1200 字节;如果客户端有 Handshake 密钥,
则它应该发送一个 Handshake 包。 

  服务端也许希望在开始加密握手之前验证客户端地址的有效性;QUIC 在完成握手之前,会使用包含在
Initial 包中的令牌来提供地址有效性验证,这个令牌在连接建立阶段通过 Retry 包(
详见 8.1.1 小节)传输给客户端,或者在之前的连接上通过 NEW_TOKEN 帧(详见 8.1.2 小节)来
传输给客户端。
  除了在地址验证之前强制限制发送的数据量,服务端还会被拥塞控制限制可以发送多少数据;
而客户端只被拥塞控制限制。

8.1.1. Address Validation using Retry Packets

  一旦收到客户端的 Initial 包,服务端可以通过发送包含令牌的 Retry 包来请求客户端地址有效性
验证;客户端在收到这个 Retry 包后必须将该令牌附加待发送的 Initial 包中(同一条连接)。服
务端在收到带有令牌的 Initial 包时,可以选择中止连接,或者允许该包被继续处理。

  只要攻击者不可能为它自己的地址生成一个有效的令牌,那么合法客户端就可以通过返回服务端
的令牌来向服务端证明自己的合法性。

  服务端可以使用 Retry 包来使状态延后转移,这增加了连接建立的处理成本。要求服务端提供一
个不同的连接 ID 以及传输参数 original_connection_id(18.2 小节所定义),将强制服务端证明
自己或与自己交互的实体接收到了客户端的原始 Initial 包(译者注:否则任何实体都可以更换连接 
ID)。 Retry 包的使用见下图:

8.1.2. Address Validation for Future Connections

  服务端可以在一次连接中为客户端提供一个用于验证地址有效性的令牌,这个令牌也可用于随后的连接。
地址有效性验证对 0-RTT 尤其重要,因为服务端可能会向客户端发送大量的数据来响应 0-RTT 数据。

  服务端使用 NEW_TOKEN 帧(详见 19.7 小节)向客户端提供一个验证地址有效性的令牌,这个令牌可
以用于随后的连接。客户端必须在后续连接的 Initial 包中包含这个令牌来验证地址的有效性,除非收到一
个用于替换旧令牌的 Retry 包,客户端不可以在后续连接中使用从 Retry 包中获取的令牌;服务端可以丢
弃未带合法令牌的 Initial 包。

  令牌需要以这样的方式去构造,即允许服务端区分它是否来自 Retry 包。

  令牌不可以包含未加密的特殊信息,这些信息可以被监听者利用并将令牌与连接关联起来。例如,它不
能包含连接 ID,或者地址信息,除非这些信息是加密的。

  不像在 Retry 中创建的令牌,其他令牌在创建到被使用有一段时间差。因此,令牌应该有一个过期时间,
可以是一个明确的过期时间,或者是一个可以用于动态计算过期时间的时间戳。服务端可以存储这个过期
时间,或者把过期时间加密在令牌中。

  客户端的两条连接不会共用同一个端口,因此验证端口是不可能成功的。

  如果客户端从之前连接的 NEW_TOKEN 帧收到一个令牌,并且客户端认为之前连接与当前连接是同样
的服务端,那么它应该把收到的这个令牌包含在 Initial 包的 Token 域,这样可以减少一个用于验证客户端
地址的 RTT。

  令牌允许服务端将创建令牌的连接和使用该令牌的连接建立关联。客户端如果不想继续使用某个服务端
的令牌,可以丢弃从 NEW_TOKEN 获取的令牌。从 Retry 包中获取的令牌必须在当前尝试建连时被立即
使用,而不应在后续的尝试建连时被使用。

  客户端不应该在不同连接中复用一个令牌。复用令牌将允许网络链路中的节点将连接和令牌建立关联
(详见 9.5 小节)。客户端不可以复用一个令牌除非它相信本端在最后一次使用令牌后发生了网络切换
(本地 IP 或网卡改变)。客户端需要重新启动连接,如果在握手完成前发生了   本地地址的任何改变。

  客户端可能在一条连接上收到多个令牌。假如不讨论令牌与连接的关联性问题,任何令牌是可以用于任
何尝试建连的过程。服务端可以发送额外的令牌来使得多个尝试建连的地址有效,或者替换旧的已失效令
牌。对于客户端来说,这样的二义性意味着发送最近未使用的令牌是更高效的做法。即使保存使用旧的令
牌没有负面影响,客户端可以认为在向服务端验证地址有效性时,旧令牌的价值会比较小。

  当服务端接收到带有验证地址有效性的令牌的 Initial 包时,它必须尝试验证令牌的合法性,除非它
已经完成了地址有效性验证。如果令牌是非法的,服务端应该认为客户端的地址无效,并可能发送一个
Retry 包。如果地址有效性验证成功,服务端应该允许握手继续进行。

    注意:把客户端当成是无效的而不是直接把包丢弃的根本原因在于,客户端也许在之前的连接上通过 
  NEW_TOKEN 帧接收了令牌,如果服务端丢失了状态信息则无法验证另外的有效性,如果丢弃了包那
  么会导致连接失败。服务端应该把 NEW_TOKEN 帧和 Retry 包中的令牌按不同的方式编码,而且对于 
  Retry 包中的令牌的验证需要更加严格。

  在一个无状态设计中,服务端可以使用加密认证的令牌来向客户端传递随后在服务端可以恢复的信息,
也可以使用这样的令牌来验证客户端地址的有效性。令牌未被集成到加密握手中,因此它们未被认证。
例如,客户端可以重复使用一个令牌;为了相关攻击利用这个特性,服务端    可以限制令牌只包含用于
验证客户端地址的信息。

  攻击者可以重放令牌从而使服务端作为 DDOS 攻击的放大器。为了免受这类攻击的伤害,服务端应该
确保通过 Retry 包发送的令牌只在较短的一段时间内有效。通过 NEW_TOKEN 帧(详见 19.7 小节)提
供的令牌可以有较长的有效期,但不应该在一段较短的时间内被接受多次。如果可能的话,鼓励服务端
只允许令牌的有效次数为一。

8.1.3. Address Validation Token Integrity

  验证地址有效性的令牌必须难以被猜到,在令牌中包含一个足够大的随机值可以保证这一点,但需要服
务端记住发给某个客户端的随机值。
  
  基于令牌的方案允许服务端将与地址有效性验证的状态转移到客户端。为了是这种设计能够起作用,令
牌必须被完整性保护防止被客户意外端修改或者篡改。没有完整性保护的话,恶意客户端可以生成或者猜
到可以被服务端接受的随机值。只有服务端会要求访问令牌的完整性保护密钥。
  
  不需要为令牌单独指定一个格式,因为令牌既由服务端生成,又由它自己消费。令牌可以包含客户端的
地址信息(IP 和 端口)、时间戳以及服务端在验证令牌有效时需要的任何信息。

8.2. Path Validation

  在连接迁移(详见 9.6 小节)的时候正在迁移的一端会使用路径有效性来确认一个新的本地地址到对端
的可达性。在路径有效性验证中,端点会测试一个特定的本地地址与一个特定的对端地址的可达性,地址
是 IP、端口的两元组。
  
  路径有效性会测试能发送包到对端并且能从对端收到包。重要的是,它会验证从迁移端收到的包没有携
带伪造的源地址。

  任何一端都可以在任何时候验证路径有效性,比如,一个端点可以检查对端在一段静默期后是否仍然
是它原来的地址。

  路径有效性并不是被设计为一种 NAT 的穿透机制,尽管路径有效性对于建立支持穿透的 NAT 绑定来
说是高效的,但预期是对端在没有先发送包的情况下可以收到包。高效的 NAT 穿透需要额外的同步机
制,而这种机制在这里并没有提供。

  端点可以把 PATH_CHALLENGE 和 PATH_RESPONSE 帧与其他帧组合发送。特别地,端点可以填
充携带 PATH_CHALLENGE 帧的包来发现 PMTU,也可以将 PATH_RESPONSE 与它自己的 
PATH_CHALLENGE 组合发送。

  当探测新的路径的时候,端点希望保证对端有一个没有使用的连接 ID 来发送响应。端点可以在同一个
包中发送 NEW_CONNECTION_ID 和 PATH_CHALLENGE 帧,这可以保证对端有一个未使用的连接
ID 用于发送响应。

8.3. Initiating Path Validation

  端点在被验证的路径上发送包含一个随机值的 PATH_CHALLENGE 帧来验证路径的有效性。
  
  端点可以发送多个 PATH_CHALLENGE 帧确保被送达对方,然而,端点不应该在同一个包中发送多个
PATH_CHALLENGE 帧。端点也不应以高于 Initial 的频率发送 PATH_CHALLENGE 帧,这样可以确保
连接迁移不会在新路径上增加连接建立的成本。

  端点必须在每一个 PATH_CHALLENGE 帧中使用不可预测的数据,从而可以将 PATH_CHALLENGE 帧
与对端的响应关联起来。

8.4. Path Validation Responses

  在收到 PATH_CHALLENGE 帧时,端点必须立即通过 PATH_RESPONSE 帧回显 PATH_CHALLENGE 
帧中的数据。
  端点最多可以为每一个 PATH_CHALLENGE 帧响应一个 PATH_RESPONSE 帧(详见 13.3 小节)。
对端发送多个 PATH_CHALLENGE 帧是为了确保可以收到 PATH_RESPONSE 帧。

8.5. Successful Path Validation

  一个新的地址只有在收到 PATH_RESPONSE 帧时被认为是有效地,且该帧必须包含之前 
PATH_CHALLENGE 帧的数据。收到包含 PATH_CHALLENGE 帧的包的确认并不足以证明路径有效,
因为这个确认可以被一个恶意的端点伪造。

8.6. Failed Path Validation

  验证路径有效只有在尝试验证的一方主动放弃时才会失败。

  端点应该基于定时器来主动放弃验证路径有效,在设置这个定时器时,实现需要考虑到新的路径的 RTT 可
能比原来路径的长,建议设为当前 PTO 三倍大小的值与 QUIC-RECOVERY 中定义的初始超时值
(2*kInitialRtt)的较大值,即:
   validation_timeout = max(3*PTO, 6*kInitialRtt)
 注意,端点可以在新的路径接收包含其他帧的包,但为了成功验证路径有效,PATH_RESPONSE 帧以及合
 适的数据是需要的。

  当端点主动放弃验证路径有效时,即认为该路径不可用。这不一定意味着是一个连接失败,端点可以继续
在其他路径发送包。如果没有可用的路径,端点可以等待直到有一个新路径可用,或者关闭连接。
  
  除了失败还有其他原因导致放弃验证路径有效。主要是当一个连接开始迁移到新的路径时,一个旧路径有
效性的验证正在处理。

相关链接

QUIC-RECOVERY

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章