Skip to content

Commit

Permalink
fix: properly handle invalid data sent by a malicious websocket client
Browse files Browse the repository at this point in the history
**IMPORTANT SECURITY FIX**

A malicious client could send a specially crafted HTTP request,
triggering an uncaught exception and killing the Node.js process:

> RangeError: Invalid WebSocket frame: RSV2 and RSV3 must be clear
>   at Receiver.getInfo (/.../node_modules/ws/lib/receiver.js:176:14)
>   at Receiver.startLoop (/.../node_modules/ws/lib/receiver.js:136:22)
>   at Receiver._write (/.../node_modules/ws/lib/receiver.js:83:10)
>   at writeOrBuffer (internal/streams/writable.js:358:12)

This bug was introduced by [1], included in `engine.io@4.0.0`, so
previous releases are not impacted.

[1]: f3c291f

Thanks to Marcus Wejderot from Mevisio for the responsible disclosure.

Backported from master: c0e194d
  • Loading branch information
darrachequesne committed Jan 11, 2022
1 parent 9534355 commit a70800d
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 3 deletions.
3 changes: 0 additions & 3 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,6 @@ class Server extends EventEmitter {
client.maybeUpgrade(transport);
}
} else {
// transport error handling takes over
socket.removeListener("error", onUpgradeError);

this.handshake(req._query.transport, req);
}

Expand Down
40 changes: 40 additions & 0 deletions test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,46 @@ describe("server", () => {
}
);
});

it("should not throw when the client sends invalid data during the handshake (ws only)", done => {
listen(port => {
// will throw "RangeError: Invalid WebSocket frame: RSV2 and RSV3 must be clear"
request
.get(`http://localhost:${port}/engine.io/`)
.set("connection", "upgrade")
.set("upgrade", "websocket")
.set("Sec-WebSocket-Version", "13")
.set("Sec-WebSocket-Key", "DXR4dX615eRds8nRmlhqtw==")
.query({ transport: "websocket", EIO: 4 })
.send("test")
.end(() => {});

setTimeout(done, 50);
});
});

it("should not throw when the client sends invalid data during the handshake (upgrade)", done => {
listen(port => {
request
.get(`http://localhost:${port}/engine.io/`)
.query({ transport: "polling", EIO: 4 })
.end((err, res) => {
const sid = JSON.parse(res.text.substring(1)).sid;

request
.get(`http://localhost:${port}/engine.io/`)
.set("connection", "upgrade")
.set("upgrade", "websocket")
.set("Sec-WebSocket-Version", "13")
.set("Sec-WebSocket-Key", "DXR4dX615eRds8nRmlhqtw==")
.query({ transport: "websocket", EIO: 4, sid })
.send("test")
.end(() => {});

setTimeout(done, 50);
});
});
});
});

describe("handshake", () => {
Expand Down

0 comments on commit a70800d

Please sign in to comment.