認証ハンドシェイク
クライアントポートとクラスタのRaftポートの両方でバイト単位まで同一に使われる共有 ステップです。接続が確立されると(TLSを使う場合はTLSハンドシェイク完了後)、サーバー が先に話し、チャレンジを送ります。改行(\n)区切りの2行のテキストのやり取りで、 接続ごとに1回行われます。
ポートによって異なるのは検証に使うトークンセットだけです — クライアントポートは client_tokensと、Raftポートはcluster_tokensと照合します。Raftポート固有のトークン ルール(どのトークンが送られるか、無停止でトークンをローテーションする方法)は 接続と認証 (クラスタ)を参照してください。
フロー
接続元 (クライアント・ピア)
サーバー
TCP接続 · (TLSハンドシェイク)
チャレンジ: SHA-256 ␣ nonce
digest = SHA-256(token ∥ nonce) · 43文字
トークンリスト全体と定数時間で比較
成功 → 応答なし、プロトコルが即座に開始
最初のリクエストをすぐに送信 (例: A · 獲得)
失敗した場合
E · auth_failed → 接続を閉じる
リクエストレスポンス
1. チャレンジ(サーバー → 接続元)
構造refresh
<hash> <nonce>\n 例: SHA-256 aB3dEf_g\n| フィールド | 内容 |
|---|---|
hash | ダイジェストアルゴリズム名。現在は常にSHA-256で、サーバーはそれ以外を受け付けない |
nonce | 8文字のbase64urlランダム値。フレーミングは改行区切りのため、長さは将来伸びる可能性がある — 接続元は最初のスペース以降のすべてをnonceとして扱う必要がある |
2. 応答(接続元 → サーバー)
構造refresh
<digest>\n
digest = base64url_nopad( SHA-256( token_bytes ∥ nonce_bytes ) )(∥はバイト連結です — nonce文字列のASCIIバイトが、トークンの生バイトの直後に そのまま連結されます)
- base64urlはパディングなしのURLセーフな文字集合(
A–Z a–z 0–9 - _)です。SHA-256の ダイジェストは常に43文字です。 - サーバーは設定されたトークンリスト全体に対して定数時間比較で検証します — どのトークンが一致したか、比較がどこまで進んだかは、タイミングから一切漏れません。
- トークンが設定されていないサーバーは空トークン
""を1つだけ受け付けます。この 場合、digest = base64url(SHA-256(nonce))を送れば通過します。ハンドシェイク ステップ自体を省略することは決してできません。 - サーバーが読み取る応答の行は256バイトが上限です。
3. 結果
- 成功: サーバーは何も送らず、そのままメイン プロトコルへ切り替わります — クライアントポートではバイナリフレームロックプロトコル、 Raftポートでは長さプレフィックス付きRPC。最初の リクエストをすぐに送ってください。
- 失敗: サーバーは
E auth_failedを送って接続を 閉じます。接続が切れたり、ハンドシェイクの途中で行の形式が不正だったりした場合は、 エラーフレームなしで静かに閉じられることもあります。
用語
- challenge-response — 秘密(トークン)を直接送る代わりに、サーバーが使い捨ての チャレンジを提示し、接続元がその答えだけを返すことで秘密を知っていることを証明する 認証方式。
- nonce — 一度だけ使われる数値。接続のたびに変わるため、盗まれた応答を再利用する リプレイ攻撃ができません。
- 定数時間比較 — どこまで一致したかに関わらず常に同じ時間がかかる比較で、秘密を 漏らしかねないタイミング攻撃を封じます。
- base64url — URLセーフな文字集合(
A–Z a–z 0–9 - _)のみを使うbase64の変種。 ここではパディング(=)なしで使われます。