瀏覽代碼

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.
metsw24-max 3 天之前
父節點
當前提交
c03af246fc
共有 1 個文件被更改,包括 16 次插入 和 9 次删除
  1. 16 9
      httplib.h

+ 16 - 9
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<unsigned char>((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<char *>(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<unsigned char *>(&key_bytes[0]),
+                    key_bytes.size());
   auto client_key = base64_encode(key_bytes);
 
   req.headers.erase("Upgrade");