Преглед на файлове

fix(brainstorming): cap websocket frame payloads

Rahul преди 3 месеца
родител
ревизия
d7c260a978
променени са 2 файла, в които са добавени 26 реда и са изтрити 2 реда
  1. 11 2
      skills/brainstorming/scripts/server.cjs
  2. 15 0
      tests/brainstorm-server/ws-protocol.test.js

+ 11 - 2
skills/brainstorming/scripts/server.cjs

@@ -7,6 +7,7 @@ const path = require('path');
 
 const OPCODES = { TEXT: 0x01, CLOSE: 0x08, PING: 0x09, PONG: 0x0A };
 const WS_MAGIC = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
+const MAX_FRAME_PAYLOAD_BYTES = 10 * 1024 * 1024;
 
 function computeAcceptKey(clientKey) {
   return crypto.createHash('sha1').update(clientKey + WS_MAGIC).digest('base64');
@@ -53,10 +54,18 @@ function decodeFrame(buffer) {
     offset = 4;
   } else if (payloadLen === 127) {
     if (buffer.length < 10) return null;
-    payloadLen = Number(buffer.readBigUInt64BE(2));
+    const extendedLen = buffer.readBigUInt64BE(2);
+    if (extendedLen > BigInt(MAX_FRAME_PAYLOAD_BYTES)) {
+      throw new Error('WebSocket frame payload exceeds maximum allowed size');
+    }
+    payloadLen = Number(extendedLen);
     offset = 10;
   }
 
+  if (payloadLen > MAX_FRAME_PAYLOAD_BYTES) {
+    throw new Error('WebSocket frame payload exceeds maximum allowed size');
+  }
+
   const maskOffset = offset;
   const dataOffset = offset + 4;
   const totalLen = dataOffset + payloadLen;
@@ -351,4 +360,4 @@ if (require.main === module) {
   startServer();
 }
 
-module.exports = { computeAcceptKey, encodeFrame, decodeFrame, OPCODES };
+module.exports = { computeAcceptKey, encodeFrame, decodeFrame, OPCODES, MAX_FRAME_PAYLOAD_BYTES };

+ 15 - 0
tests/brainstorm-server/ws-protocol.test.js

@@ -329,6 +329,21 @@ function runTests() {
     assert.strictEqual(result.payload.length, 65536);
   });
 
+  test('rejects oversized 64-bit frames before payload allocation', () => {
+    const mask = Buffer.from([0x00, 0x00, 0x00, 0x00]);
+    const header = Buffer.alloc(14);
+    header[0] = 0x81; // FIN + TEXT
+    header[1] = 0x80 | 127; // masked, 64-bit length
+    header.writeBigUInt64BE(BigInt(ws.MAX_FRAME_PAYLOAD_BYTES) + 1n, 2);
+    mask.copy(header, 10);
+
+    assert.throws(
+      () => ws.decodeFrame(header),
+      /exceeds maximum allowed size/i,
+      'oversized advertised payload must be rejected from header alone'
+    );
+  });
+
   // ========== Close Frame with Status Code ==========
   console.log('\n--- Close Frame Details ---');