Skip to content
uencoder
TUTORIAL

How to Implement Secure WebSockets

Establish and maintain secure WebSocket (WSS) connections with proper authentication, origin validation, and message integrity.

Problem

WebSocket connections can be hijacked, lack authentication, or accept messages from unauthorized origins. You need to implement secure WebSockets (wss://) with proper authentication, origin checking, and protection against common attacks.

Prerequisites

  • Understanding of WebSocket protocol (RFC 6455)
  • Familiarity with TLS and the wss:// scheme
  • Knowledge of HTTP authentication and CORS

Steps

  1. 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.

    Input
    GET /ws HTTP/1.1 | Upgrade: websocket | Authorization: Bearer <token>
    Output
    HTTP 101 Switching Protocols (if auth valid) | HTTP 401 (if auth fails)
  2. 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.

    Input
    Origin: https://trusted.example.com
    Output
    origin_check: pass | (Origin: https://evil.com -> reject 403)
  3. 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.

    Input
    message: { type: chat, text: hello }
    Output
    valid: true | processed | (oversized: reject 1009 Message Too Big)
  4. 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.

    Input
    token expired mid-session
    Output
    close: 1008 Policy Violation | reason: auth expired

Expected result

Secure WebSocket connections with TLS, per-connection authentication, origin validation, message schema enforcement, and rate limiting.

Common errors

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.

Troubleshooting

  • 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.

Security limits

  • 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.

Related tools

Related glossary

Related tasks

Ready to run it?

References