WittCode💻

Does HTTPS Secure WebSockets?

By

Learn how to secure WebSocket connections from ws to wss using HTTPS. We will go over the relationship between HTTP and WebSocket, the HTTP headers involved, and what a TLS handshake is.

Table of Contents 📖

WebSockets and HTTP

WebSocket connections use two protocols: ws (insecure) and wss (secure). This is similar to how HTTP uses two protocols: http (insecure) and https (secure). Websocket connections are also upgraded HTTP connections. This means that if you are using HTTPS, the WebSocket will inherit the security properties of HTTPS. In other words, the initial WebSocket handshake occurs over the same secure TLS/SSL connection used by HTTPS.

INFO: During an HTTPS connection, before any data is transmitted, the client and server exchange keys and negotiate encryption parameters using the TLS protocol. Because the WebSocket handshake piggybacks on HTTPS, the initial handshake and any subsequent WebSocket messages are also encrypted.

Upgrading WebSockets

WebSocket connections start as HTTP requests with an Upgrade HTTP header. This header indicates the desire to switch protocols to WebSocket. If this initial HTTP request is made over HTTPS, then the upgraded WebSocket connection is encrypted and secured due to the underlying TLS/SSL encryption. For example, consider the following Nginx SSL configuration:

server {
    listen ${NGINX_PORT_SSL} ssl;
    listen [::]:${NGINX_PORT_SSL} ssl;
    server_name ${NGINX_HOST};

    ssl_certificate /etc/letsencrypt/live/wittcode.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/wittcode.com/privkey.pem;

    root /usr/share/nginx;

    location / {
        try_files $uri $uri/ $uri.html /images/404.png;
    }

    location /ws/ {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";

        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
        proxy_connect_timeout 60s;

        proxy_pass http://${SERVER_HOST}:${SERVER_PORT};
    }
}

INFO: The ssl_certificate directive is the path to the SSL certificate file, ensuring the HTTPS connection is encrypted and the ssl_certificate_key directive is the path to the private key for the SSL certificate, used for establishing secure communication.

This Nginx server block handles both regular HTTP requests and WebSocket connections over HTTPS with the use of SSL/TLS certificates. The location /ws/ block uses the proxy_pass directive to forward the WebSocket connection to the WebSocket server. This proxied WebSocket is secure because it uses HTTPS and ensures encryption for both the handshake and subsequent WebSocket communication.

Client Code

When it comes to the client library, most will pick up on the protocol being used automatically. For example, the following will detect using HTTPS when served by https://wittcode.com (production) and HTTP when served by http://localhost (development).

const socket = io({
  path: '/ws/'
});