mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-25 12:14:41 +00:00
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.
This commit is contained in:
1 parent
2c918f27ee
commit
c03af246fc
1 file changed
+16
-9
@@ -5604,6 +5604,18 @@ inline bool is_websocket_upgrade(const Request &req) {
|
|||||||
return true;
|
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<unsigned char>((v >> (b * 8)) & 0xFFu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline bool write_websocket_frame(Stream &strm, ws::Opcode opcode,
|
inline bool write_websocket_frame(Stream &strm, ws::Opcode opcode,
|
||||||
const char *data, size_t len, bool fin,
|
const char *data, size_t len, bool fin,
|
||||||
bool mask) {
|
bool mask) {
|
||||||
@@ -5639,10 +5651,8 @@ inline bool write_websocket_frame(Stream &strm, ws::Opcode opcode,
|
|||||||
|
|
||||||
if (mask) {
|
if (mask) {
|
||||||
// Generate random mask key
|
// Generate random mask key
|
||||||
thread_local std::mt19937 rng(std::random_device{}());
|
|
||||||
uint8_t mask_key[4];
|
uint8_t mask_key[4];
|
||||||
auto r = rng();
|
fill_random_bytes(mask_key, sizeof(mask_key));
|
||||||
std::memcpy(mask_key, &r, 4);
|
|
||||||
if (strm.write(reinterpret_cast<char *>(mask_key), 4) < 0) { return false; }
|
if (strm.write(reinterpret_cast<char *>(mask_key), 4) < 0) { return false; }
|
||||||
|
|
||||||
// Write masked payload in chunks
|
// 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,
|
inline bool perform_websocket_handshake(Stream &strm, Request &req,
|
||||||
WebSocketUpgradeResponse &upgrade) {
|
WebSocketUpgradeResponse &upgrade) {
|
||||||
// Generate random Sec-WebSocket-Key
|
// Generate a random 16-byte Sec-WebSocket-Key (RFC 6455 Section 4.1)
|
||||||
thread_local std::mt19937 rng(std::random_device{}());
|
|
||||||
std::string key_bytes(16, '\0');
|
std::string key_bytes(16, '\0');
|
||||||
for (size_t i = 0; i < 16; i += 4) {
|
fill_random_bytes(reinterpret_cast<unsigned char *>(&key_bytes[0]),
|
||||||
auto r = rng();
|
key_bytes.size());
|
||||||
std::memcpy(&key_bytes[i], &r, (std::min)(size_t(4), size_t(16 - i)));
|
|
||||||
}
|
|
||||||
auto client_key = base64_encode(key_bytes);
|
auto client_key = base64_encode(key_bytes);
|
||||||
|
|
||||||
req.headers.erase("Upgrade");
|
req.headers.erase("Upgrade");
|
||||||
|
|||||||
Reference in new issue
Block a user