メインコンテンツまでスキップ

4. Opening Handshake (オープニングハンドシェイク)

WebSocketプロトコルのオープニングハンドシェイク (Opening Handshake) は、既存のHTTPインフラストラクチャと互換性を持つように設計されています。このハンドシェイクはHTTPアップグレードリクエストです。

4.1 Client Requirements (クライアント要件)

クライアントが送信するハンドシェイクリクエストは、以下の形式の有効なHTTPリクエストでなければなりません:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Extensions: permessage-deflate

必須ヘッダーフィールド

Host

  • サーバーのホストとポート番号を含む
  • HTTP/1.1仕様に準拠

Upgrade: websocket

  • このヘッダーを含まなければならない (MUST)
  • 値は"websocket"(大文字小文字を区別しない)

Connection: Upgrade

  • このヘッダーを含まなければならない (MUST)
  • これがアップグレードリクエストであることを示す

Sec-WebSocket-Key

  • このヘッダーを含まなければならない (MUST)
  • ランダムに生成された16バイトの値で、Base64エンコードされている
  • サーバーがWebSocketプロトコルを理解していることを検証するために使用

Sec-WebSocket-Version: 13

  • このヘッダーを含まなければならない (MUST)
  • 現在のバージョン番号は13

オプションのヘッダーフィールド

Origin

  • ブラウザクライアントは含まなければならない (MUST)
  • 非ブラウザクライアントは含んでもよい (MAY)
  • サーバー側のセキュリティ検証に使用

Sec-WebSocket-Protocol

  • 任意 (OPTIONAL)
  • クライアントがサポートするサブプロトコルのリストを指定
  • 複数の値はカンマで区切る

Sec-WebSocket-Extensions

  • 任意 (OPTIONAL)
  • クライアントがサポートする拡張を指定
  • 形式: extension-name [; parameter=value]*

4.2 Server-Side Requirements (サーバー側要件)

サーバーはクライアントハンドシェイクを検証し、適切なレスポンスを返さなければなりません。

4.2.1 Reading the Client's Opening Handshake (クライアントハンドシェイクの読み取り)

サーバーは以下を検証しなければなりません (MUST):

  1. HTTPメソッド: GETでなければならない
  2. HTTPバージョン: 少なくともHTTP/1.1
  3. 必須ヘッダー: Host、Upgrade、Connection、Sec-WebSocket-Key、Sec-WebSocket-Versionが存在しなければならない
  4. Sec-WebSocket-Version: 13(またはサーバーがサポートするバージョン)でなければならない

検証が失敗した場合、サーバーは適切なHTTPエラーステータスコードを返すべきです (SHOULD)。

4.2.2 Sending the Server's Opening Handshake (サーバーハンドシェイクの送信)

検証が成功した場合、サーバーはハンドシェイクレスポンスを送信しなければなりません (MUST):

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

Sec-WebSocket-Acceptの計算

これはハンドシェイクの重要な部分です。サーバーは以下の手順で計算しなければなりません:

  1. クライアントのSec-WebSocket-Key値を取得
  2. 固定のGUID文字列と連結: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11
  3. 連結された文字列のSHA-1ハッシュを実行
  4. ハッシュ結果をBase64エンコード

アルゴリズム例 (JavaScript):

const crypto = require('crypto');

function generateAcceptKey(clientKey) {
const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
const concatenated = clientKey + GUID;
const hash = crypto.createHash('sha1').update(concatenated).digest();
return hash.toString('base64');
}

// 例
const clientKey = 'dGhlIHNhbXBsZSBub25jZQ==';
const acceptKey = generateAcceptKey(clientKey);
console.log(acceptKey); // s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

4.3 Collecting Extensions and Subprotocols (拡張とサブプロトコルの収集)

サブプロトコルのネゴシエーション

クライアントはSec-WebSocket-Protocolヘッダーに複数のサブプロトコルをリストできます:

Sec-WebSocket-Protocol: chat, superchat

サーバーはクライアントのリストから1つを選択(または選択しない)し、レスポンスで返さなければなりません (MUST):

Sec-WebSocket-Protocol: chat

サーバーがクライアントが要求したサブプロトコルのいずれもサポートしていない場合、Sec-WebSocket-Protocolヘッダーを省略できます。

拡張のネゴシエーション

拡張のネゴシエーションはSec-WebSocket-Extensionsヘッダーを通じて行われます:

クライアントリクエスト:

Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

サーバーレスポンス:

Sec-WebSocket-Extensions: permessage-deflate

サーバーは拡張を受け入れ、パラメータを変更、または拒否できます。

4.4 Supporting Multiple Versions (複数バージョンのサポート)

サーバーがクライアントが要求したバージョンをサポートしていない場合、HTTP 426 Upgrade Requiredを返し、サポートされているバージョンをリストしたSec-WebSocket-Versionヘッダーを含めるべきです (SHOULD):

HTTP/1.1 426 Upgrade Required
Sec-WebSocket-Version: 13, 8, 7

ハンドシェイクの完全な例

成功したハンドシェイク

クライアント → サーバー:

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13
Origin: http://example.com

サーバー → クライアント:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

ハンドシェイク失敗の例

サポートされていないバージョン:

HTTP/1.1 426 Upgrade Required
Sec-WebSocket-Version: 13

Originが受け入れられない:

HTTP/1.1 403 Forbidden

セキュリティに関する考慮事項

  1. Originの検証: サーバーはOriginヘッダーを検証し、クロスサイト攻撃を防ぐべきです
  2. TLSの使用: 本番環境ではwss://を使用
  3. すべてのヘッダーの検証: すべての必須ヘッダーが存在し、適切にフォーマットされていることを確認
  4. 接続の制限: DoS攻撃を防ぐためのレート制限を実装

参考リンク