Ticketing
文档

认证握手

客户端端口与集群 Raft 端口按字节完全一致共用的一个步骤。 一旦连接建立 (如果使用 TLS,则在 TLS 握手完成之后),服务器先发言,发送一个 challenge。 这是一次两行、以换行符(\n)分隔的文本交换,每个连接执行一次

不同端口之间唯一的区别是使用哪一套 token 进行校验 —— 客户端端口对照 client_tokens 校验,Raft 端口对照 cluster_tokens 校验。Raft 端口专属的 token 规则(发送哪个 token、如何实现零停机 token 轮换)见 连接与认证 (集群)

流程

连接方 (客户端 · 对端)
服务器
TCP 连接 · (TLS 握手)
challenge: SHA-256 ␣ nonce
digest = SHA-256(token ∥ nonce) · 43 字符
对整个 token 列表进行恒定时间比较
成功 → 不回复,协议立即开始
立即发送第一个请求 (例如 A · 获取)
若失败
E · auth_failed → 连接关闭
请求响应

1. Challenge(服务器 → 连接方)

结构refresh
<hash> <nonce>\n            例如 SHA-256 aB3dEf_g\n
字段内容
hash摘要算法名称。目前始终为 SHA-256,服务器不接受其他任何值
nonce一个 8 字符的 base64url 随机值。分帧方式是以换行符分隔的,因此其长度未来可能变长 —— 连接方必须把第一个空格之后的全部内容都当作 nonce

2. Response(连接方 → 服务器)

结构refresh
<digest>\n

digest = base64url_nopad( SHA-256( token_bytes ∥ nonce_bytes ) )

( 表示字节拼接 —— nonce 字符串的 ASCII 字节直接附加在 token 的原始字节之后)

  • base64url 是不带填充的 URL 安全字符集(A–Z a–z 0–9 - _)。SHA-256 摘要 的长度始终为 43 个字符
  • 服务器使用恒定时间比较对照整个已配置的 token 列表进行校验 —— 哪个 token 匹配上了、比较进行到了多远,都不会通过耗时泄露出去。
  • 未配置任何 token 的服务器会接受单个空 token ""。此时发送 digest = base64url(SHA-256(nonce)) 即可通过。握手这一步本身永远不能 被跳过。
  • 服务器读取的 response 行长度上限为 256 字节。

3. 结果

  • 成功:服务器不发送任何内容,直接切换进主协议 —— 客户端端口进入 二进制帧锁协议,Raft 端口进入 带长度前缀的 RPC。此后立即发送第一个请求。
  • 失败:服务器发送 E auth_failed 并关闭连接。如果连接在握手中途断开或某一行格式错误,也可能直接静默关闭, 不发送任何错误帧。

术语

  • challenge-response —— 一种认证方案:服务器不要求直接发送密钥(token), 而是提出一次性的 challenge,连接方只需回传答案,以此证明自己知道该密钥。
  • nonce —— 一个只使用一次的数字。每次连接都会变化,因此被窃取的 response 无法在重放攻击中被再次使用。
  • 恒定时间比较 (constant-time compare) —— 一种无论比较进行到多远、 耗时都保持恒定的比较方式,从而封堵住原本可能泄露密钥的计时攻击。
  • base64url —— 一种只使用 URL 安全字符集(A–Z a–z 0–9 - _)的 base64 变体。此处使用时不带填充(=)。