セキュアな WebSocket を実装する方法
適切な認証、オリジン検証、メッセージ整合性を備えたセキュアな WebSocket(WSS)接続を確立・維持します。
问题
WebSocket 接続は乗っ取り、認証の欠如、不正なオリジンからのメッセージ受信などの危険に晒されます。適切な認証、オリジンチェック、一般的な攻撃への対策を備えたセキュアな WebSocket(wss://)を実装する必要があります。
前提条件
- WebSocket プロトコル(RFC 6455)の理解
- TLS と wss:// スキームへの習熟
- HTTP 認証と CORS に関する知識
ステップ
-
1. Establish WSS with TLS and authentication
Always use wss:// (WebSocket Secure over TLS), never ws:// in production. Perform authentication during the WebSocket handshake: pass a token in the initial HTTP upgrade request (via Authorization header, query parameter, or Sec-WebSocket-Protocol subprotocol). Validate the token before accepting the upgrade. The server must reject the upgrade (HTTP 401/403) if authentication fails. Use the WebSocket frame encoder/decoder to understand the protocol.
入力GET /ws HTTP/1.1 | Upgrade: websocket | Authorization: Bearer <token>输出HTTP 101 Switching Protocols (if auth valid) | HTTP 401 (if auth fails) -
2. Validate the Origin header
Check the Origin header on the upgrade request against an allow-list of trusted origins. This prevents Cross-Site WebSocket Hijacking (CSWSH) where a malicious website opens a WebSocket to your server using the victim's browser credentials. Reject requests with missing or untrusted origins with HTTP 403. Do not use CORS for WebSockets — Origin checking is the WebSocket-specific mechanism. Use the URL parser to validate origin format.
入力Origin: https://trusted.example.com输出origin_check: pass | (Origin: https://evil.com -> reject 403) -
3. Implement message validation and rate limiting
Validate every incoming message against a schema (JSON Schema, protobuf) before processing. Reject malformed, oversized, or unexpected message types. Enforce a maximum message size (e.g., 1MB) and rate limit per connection (messages per second). Use ping/pong frames for keepalive and to detect dead connections. Set reasonable timeouts for idle connections. Use the JSON validator and WebSocket frame decoder for message inspection.
入力message: { type: chat, text: hello }输出valid: true | processed | (oversized: reject 1009 Message Too Big) -
4. Secure the connection lifecycle
Implement proper connection cleanup: close connections on authentication expiry, set idle timeouts, and handle close codes (1000 normal, 1001 going away, 1008 policy violation, 1011 internal error). Re-authenticate on reconnection. Never send sensitive data in broadcast messages. Log connection events for audit. For multi-server deployments, use a shared session store and authenticate on each server, not just the one that received the upgrade.
入力token expired mid-session输出close: 1008 Policy Violation | reason: auth expired
期待される結果
TLS、接続ごとの認証、オリジン検証、メッセージスキーマの強制、レートリミットを備えたセキュアな WebSocket 接続。
よくあるエラー
- Using ws:// instead of wss:// in production
- Always use wss:// (TLS). ws:// sends all data including tokens in plaintext, vulnerable to interception and modification.
- Not validating the Origin header
- Without Origin validation, any website can open a WebSocket to your server using the user's browser session. Always check Origin against an allow-list.
- Authenticating only at connection, not per-message
- For long-lived connections, the initial token may expire. Re-validate periodically or on sensitive operations. Close connections with expired credentials.
トラブルシューティング指引
- If connections drop frequently, check proxy/load balancer WebSocket support and timeout settings (e.g., Nginx proxy_read_timeout).
- If the Origin check blocks legitimate connections, ensure your CDN/proxy forwards the Origin header correctly.
- For large messages, consider chunking or using a separate file upload channel rather than sending large payloads over WebSocket.
セキュリティ上の制限
- WebSocket connections are stateful and long-lived — a compromised token remains valid until the connection closes or the token is re-validated.
- All authentication and message validation happen server-side; the client must not be trusted to enforce security policies.
- Broadcast messages can leak data to unauthorized clients if not filtered per-recipient.