Skip to content
This repository has been archived by the owner on Feb 1, 2022. It is now read-only.

feat(InspectClient): validate sec-websocket-accept response header #93

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions lib/internal/inspect_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ const kTwoBytePayloadLengthField = 126;
const kEightBytePayloadLengthField = 127;
const kMaskingKeyWidthInBytes = 4;

// This guid is defined in the Websocket Protocol RFC
// https://tools.ietf.org/html/rfc6455#section-1.3
const WEBSOCKET_HANDSHAKE_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';

function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
Expand All @@ -57,6 +61,19 @@ function unpackError({ code, message, data }) {
return err;
}

function validateHandshake(requestKey, responseKey) {
const expectedResponseKeyBase = requestKey + WEBSOCKET_HANDSHAKE_GUID;
const shasum = crypto.createHash('sha1');
shasum.update(expectedResponseKeyBase);
const shabuf = shasum.digest();

if (shabuf.toString('base64') !== responseKey) {
throw new Error(
`Websocket secret mismatch: ${requestKey} did not match ${responseKey}`
);
}
}

function encodeFrameHybi17(payload) {
var i;

Expand Down Expand Up @@ -300,8 +317,8 @@ class Client extends EventEmitter {
_connectWebsocket(urlPath) {
this.reset();

const key1 = crypto.randomBytes(16).toString('base64');
debuglog('request websocket', key1);
const requestKey = crypto.randomBytes(16).toString('base64');
debuglog('request websocket', requestKey);

const httpReq = this._http = http.request({
host: this._host,
Expand All @@ -310,7 +327,7 @@ class Client extends EventEmitter {
headers: {
Connection: 'Upgrade',
Upgrade: 'websocket',
'Sec-WebSocket-Key': key1,
'Sec-WebSocket-Key': requestKey,
'Sec-WebSocket-Version': '13',
},
});
Expand All @@ -327,7 +344,7 @@ class Client extends EventEmitter {
});

const handshakeListener = (res, socket) => {
// TODO: we *could* validate res.headers[sec-websocket-accept]
validateHandshake(requestKey, res.headers['sec-websocket-accept']);
debuglog('websocket upgrade');

this._socket = socket;
Expand Down