From c03af246fcc122c78ad4ce767fde93f78970fe21 Mon Sep 17 00:00:00 2001 From: metsw24-max Date: Thu, 15 Oct 2026 01:39:36 +0530 Subject: [PATCH] Use a strong entropy source for the WebSocket masking key (#2629) Draw the masking key and Sec-WebSocket-Key directly from std::random_device instead of a std::mt19937 seeded once with 32 bits, as RFC 6455 Section 5.3 requires an unpredictable masking key. Taking the bytes one at a time also fixes an all-zero key on 64-bit big-endian builds, where the 4-byte memcpy from the 64-bit result_type copied the zero high half. --- httplib.h | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/httplib.h b/httplib.h index d6d2d1b..97f1144 100644 --- a/httplib.h +++ b/httplib.h @@ -5604,6 +5604,18 @@ inline bool is_websocket_upgrade(const Request &req) { return true; } +// RFC 6455 Section 5.3: the masking key must be unpredictable +inline void fill_random_bytes(unsigned char *out, size_t n) { + thread_local std::random_device rd; + size_t filled = 0; + while (filled < n) { + auto v = rd(); + for (size_t b = 0; b < sizeof(v) && filled < n; ++b, ++filled) { + out[filled] = static_cast((v >> (b * 8)) & 0xFFu); + } + } +} + inline bool write_websocket_frame(Stream &strm, ws::Opcode opcode, const char *data, size_t len, bool fin, bool mask) { @@ -5639,10 +5651,8 @@ inline bool write_websocket_frame(Stream &strm, ws::Opcode opcode, if (mask) { // Generate random mask key - thread_local std::mt19937 rng(std::random_device{}()); uint8_t mask_key[4]; - auto r = rng(); - std::memcpy(mask_key, &r, 4); + fill_random_bytes(mask_key, sizeof(mask_key)); if (strm.write(reinterpret_cast(mask_key), 4) < 0) { return false; } // Write masked payload in chunks @@ -10364,13 +10374,10 @@ inline bool is_host(const std::string &s) { inline bool perform_websocket_handshake(Stream &strm, Request &req, WebSocketUpgradeResponse &upgrade) { - // Generate random Sec-WebSocket-Key - thread_local std::mt19937 rng(std::random_device{}()); + // Generate a random 16-byte Sec-WebSocket-Key (RFC 6455 Section 4.1) std::string key_bytes(16, '\0'); - for (size_t i = 0; i < 16; i += 4) { - auto r = rng(); - std::memcpy(&key_bytes[i], &r, (std::min)(size_t(4), size_t(16 - i))); - } + fill_random_bytes(reinterpret_cast(&key_bytes[0]), + key_bytes.size()); auto client_key = base64_encode(key_bytes); req.headers.erase("Upgrade");