Mastering WebSocket: Handshake, Data Frames & Node.js Examples

This article provides a comprehensive guide to WebSocket, covering its purpose, connection establishment, handshake process, data frame structure, masking algorithm, security considerations, and includes practical Node.js server and client code examples to illustrate real‑time bidirectional communication.

21CTO
21CTO
21CTO
Mastering WebSocket: Handshake, Data Frames & Node.js Examples

Overview

WebSocket adds real‑time bidirectional communication to browsers. This article explains how a WebSocket connection is established, how data is exchanged, the frame format, security attacks, and how the protocol defends against them.

What is WebSocket?

WebSocket is an application‑layer protocol introduced with HTML5 that provides full‑duplex communication over a single TCP connection, reusing the HTTP handshake channel.

Available in browsers

Supports two‑way communication

Simple to use

Key Advantages

Bidirectional communication with lower latency

Better binary support

Small control overhead (2‑10 bytes header from client to server, 4 bytes mask)

Extensible via protocol extensions (e.g., custom compression)

What to Learn

Connection establishment

Data exchange

Data‑frame format

Connection maintenance

Getting Started Example

Server (Node.js with ws )

var app = require('express')();
var server = require('http').Server(app);
var WebSocket = require('ws');
var wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {
  console.log('server: receive connection.');
  ws.on('message', function incoming(message) {
    console.log('server: received: %s', message);
  });
  ws.send('world');
});

app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});

app.listen(3000);

Client (Browser)

<script>
var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function () {
  console.log('ws onopen');
  ws.send('from client: hello');
};
ws.onmessage = function (e) {
  console.log('ws onmessage');
  console.log('from server: ' + e.data);
};
</script>

Connection Establishment (Handshake)

Client Request

GET / HTTP/1.1

Host: localhost:8080
Origin: http://127.0.0.1:3000
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw==

Key headers: Connection: Upgrade – request protocol upgrade Upgrade: websocket – target protocol Sec-WebSocket-Version: 13 – protocol version Sec-WebSocket-Key – random value used to compute the accept header

Server Response

HTTP/1.1 101 Switching Protocols

Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: Oy4NRAQ13jhfONC7bP8dTKb4PTU=

The server returns status 101 and includes Sec-WebSocket-Accept, which is the base64‑encoded SHA‑1 of the concatenation of Sec-WebSocket-Key and the magic string 258EAFA5‑E914‑47DA‑95CA‑C5AB0DC85B11.

Data‑Frame Format

Each message is composed of one or more frames. A frame consists of:

FIN (1 bit) – final fragment flag

RSV1‑3 (3 bits) – usually 0, used for extensions

Opcode (4 bits) – defines frame type (text, binary, close, ping, pong, continuation)

Mask (1 bit) – client‑to‑server frames are masked

Payload length (7 bits, 7+16 bits, or 7+64 bits) – length of the payload data

Masking‑key (0 or 4 bytes) – present when Mask=1

Payload data – optional extended data followed by application data

If the payload length is 126, the next 2 bytes give the actual length; if 127, the next 8 bytes give the length.

Masking Algorithm

For each payload byte i, the transformed byte is computed as:

j = i mod 4
transformed[i] = original[i] XOR masking-key[j]

This simple XOR operation prevents certain proxy‑cache poisoning attacks.

Data Transmission

After the handshake, communication is based on frames. The opcode determines the frame type (e.g., 0x1 for text, 0x2 for binary, 0x8 for close, 0x9 for ping, 0xA for pong). The FIN bit indicates whether the frame is the last fragment of a message.

Connection Keep‑Alive & Heartbeat

To keep idle connections alive, a ping/pong exchange is used:

Sender → Receiver: ping (opcode 0x9)

Receiver → Sender: pong (opcode 0xA)

Example (Node.js ws module):

ws.ping('', false, true);

Purpose of Sec‑WebSocket‑Key / Sec‑WebSocket‑Accept

These headers provide basic protection against accidental or malicious connections, ensure the server understands the WebSocket protocol, and prevent browsers from inadvertently upgrading ordinary AJAX requests.

Why Data Masking Exists

Masking defends against early protocol attacks such as proxy cache poisoning. It does not encrypt data; the algorithm is public, but it forces browsers to apply a transformation that many malicious clients would otherwise skip.

Proxy Cache Poisoning Attack (Illustrative)

An attacker can use a WebSocket connection to inject an HTTP request that a misbehaving proxy caches, causing a victim to receive malicious content when later requesting a legitimate resource.

Current Mitigation

The original proposal considered full encryption, but a compromise was reached: apply the masking algorithm to payloads from client to server, which raises the difficulty of the attack while keeping performance acceptable.

Conclusion

WebSocket offers many extension possibilities (compression, encryption, multiplexing). This article covered the core protocol, handshake, frame format, masking, and security considerations.

Related Links

RFC6455 – WebSocket specification: https://tools.ietf.org/html/rfc6455

Data‑frame masking details: https://tools.ietf.org/html/rfc6455#section-5.3

Data‑frame format: https://tools.ietf.org/html/rfc6455#section-5.1

Server example (ws module): https://github.com/websockets/ws#server-example

MDN WebSocket API: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets/API/Writing_WebSocket_servers

Attacks on infrastructure (masking): https://tools.ietf.org/html/rfc6455#section-10.3

Talking to Yourself for Fun and Profit (attack description): http://w2spconf.com/2011/papers/websocket.pdf

Why are WebSockets masked?: https://stackoverflow.com/questions/33250207/why-are-websockets-masked

WebSocket diagram
WebSocket diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Node.jsWebSocketreal-time communicationdata maskingHandshake
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.