Back to blog
InspectionJanuary 1, 2024Β· 15 min read

WebSocket and Real-time Connection Analysis: Monitor Live Data Flows

A practical Fusebox guide to websocket and real-time connection analysis.

WebSocket and Real-time Connection Analysis: Monitor Live Data Flows

Published: January 2024
Reading time: 9 minutes

Real-time connections power modern web experiencesβ€”chat, notifications, live updates, collaborative editing. But they also introduce security risks and performance challenges. Here's how to analyze WebSocket connections, monitor real-time data flows, and identify vulnerabilities.

Why Real-time Analysis Matters

The Hidden Data Highway

  • Persistent connections - Bypass traditional request/response security
  • Binary protocols - Harder to inspect than HTTP
  • Authentication gaps - Often implemented incorrectly
  • Data leakage - Sensitive info in real-time streams
  • Performance impact - Keep-alive overhead and reconnection storms

Real-World Incidents

Slack (2016): WebSocket token exposure allowed account takeover
Zoom (2020): WebSocket vulnerabilities enabled meeting hijacking
Discord (2021): Real-time connection leak exposed user presence
Trading Apps (2023): WebSocket injection manipulated prices
Chat Services: Regular data leaks through unencrypted WebSockets

Quick WebSocket Detection

1. Active Connection Monitor

// Monitor all WebSocket connections on the page
(function monitorWebSockets() {
  console.log('πŸ”Œ WebSocket Connection Monitor\n');
  
  const connections = new Map();
  let connectionId = 0;
  
  // Override WebSocket constructor
  const OriginalWebSocket = window.WebSocket;
  
  window.WebSocket = function(url, protocols) {
    console.log(`\nπŸ†• New WebSocket connection #${++connectionId}`);
    console.log(`   URL: ${url}`);
    if (protocols) console.log(`   Protocols: ${protocols}`);
    
    // Create real WebSocket
    const ws = new OriginalWebSocket(url, protocols);
    const id = connectionId;
    const startTime = Date.now();
    
    // Store connection info
    const connInfo = {
      id: id,
      url: url,
      protocols: protocols,
      state: 'CONNECTING',
      messagesSent: 0,
      messagesReceived: 0,
      bytesSent: 0,
      bytesReceived: 0,
      startTime: startTime,
      errors: []
    };
    
    connections.set(id, connInfo);
    
    // Monitor events
    ws.addEventListener('open', function(event) {
      connInfo.state = 'OPEN';
      connInfo.openTime = Date.now();
      console.log(`βœ… Connection #${id} opened (${connInfo.openTime - startTime}ms)`);
      
      // Check for security
      const wsUrl = new URL(url);
      if (wsUrl.protocol === 'ws:' && window.location.protocol === 'https:') {
        console.log(`   ⚠️ WARNING: Insecure WebSocket on HTTPS page!`);
        connInfo.errors.push('Insecure WebSocket');
      }
    });
    
    ws.addEventListener('message', function(event) {
      connInfo.messagesReceived++;
      const dataSize = event.data.length || event.data.size || 0;
      connInfo.bytesReceived += dataSize;
      
      // Analyze message content
      let messageType = 'unknown';
      let sensitiveData = false;
      
      if (typeof event.data === 'string') {
        messageType = 'text';
        
        // Check for sensitive data patterns
        const sensitivePatterns = [
          /password/i,
          /token/i,
          /session/i,
          /credit.?card/i,
          /ssn/i,
          /api.?key/i
        ];
        
        sensitiveData = sensitivePatterns.some(pattern => pattern.test(event.data));
        
        // Try to parse JSON
        try {
          const parsed = JSON.parse(event.data);
          messageType = parsed.type || parsed.event || 'json';
        } catch (e) {
          // Not JSON
        }
      } else if (event.data instanceof Blob) {
        messageType = 'binary';
      }
      
      console.log(`πŸ“¨ Message #${connInfo.messagesReceived} on connection #${id}`);
      console.log(`   Type: ${messageType}, Size: ${dataSize} bytes`);
      if (sensitiveData) {
        console.log(`   ⚠️ SENSITIVE DATA DETECTED!`);
        connInfo.errors.push('Sensitive data in message');
      }
    });
    
    ws.addEventListener('error', function(event) {
      connInfo.state = 'ERROR';
      connInfo.errors.push('Connection error');
      console.log(`❌ Error on connection #${id}`);
    });
    
    ws.addEventListener('close', function(event) {
      connInfo.state = 'CLOSED';
      connInfo.closeTime = Date.now();
      connInfo.duration = connInfo.closeTime - startTime;
      
      console.log(`πŸ”΄ Connection #${id} closed`);
      console.log(`   Code: ${event.code}, Reason: ${event.reason || 'none'}`);
      console.log(`   Duration: ${(connInfo.duration / 1000).toFixed(1)}s`);
      console.log(`   Messages: ${connInfo.messagesSent} sent, ${connInfo.messagesReceived} received`);
    });
    
    // Override send to monitor outgoing
    const originalSend = ws.send;
    ws.send = function(data) {
      connInfo.messagesSent++;
      connInfo.bytesSent += data.length || data.size || 0;
      
      console.log(`πŸ“€ Sending message #${connInfo.messagesSent} on connection #${id}`);
      
      return originalSend.apply(this, arguments);
    };
    
    return ws;
  };
  
  // Restore prototype
  window.WebSocket.prototype = OriginalWebSocket.prototype;
  
  // Status report
  setInterval(() => {
    if (connections.size > 0) {
      console.log('\nπŸ“Š WebSocket Status Report');
      console.log('─'.repeat(40));
      
      connections.forEach((conn, id) => {
        if (conn.state === 'OPEN') {
          const duration = ((Date.now() - conn.startTime) / 1000).toFixed(1);
          const rate = conn.messagesReceived > 0 ? 
            (conn.messagesReceived / duration).toFixed(1) : 0;
          
          console.log(`Connection #${id}: ${conn.state}`);
          console.log(`  Duration: ${duration}s`);
          console.log(`  Messages: ${conn.messagesReceived} (${rate} msg/s)`);
          console.log(`  Data received: ${(conn.bytesReceived / 1024).toFixed(1)}KB`);
          if (conn.errors.length > 0) {
            console.log(`  ⚠️ Issues: ${conn.errors.join(', ')}`);
          }
        }
      });
    }
  }, 10000);
  
  console.log('WebSocket monitoring active...');
})();

2. Socket.io Detection and Analysis

// Detect and analyze Socket.io connections
function analyzeSocketIO() {
  console.log('\nπŸ” Socket.io Analysis\n');
  
  if (!window.io) {
    console.log('❌ Socket.io not detected');
    return;
  }
  
  console.log('βœ… Socket.io detected!');
  
  // Find all socket instances
  const sockets = [];
  
  // Common Socket.io instance locations
  const possibleSockets = [
    window.socket,
    window.io.socket,
    window.app?.socket,
    window.socketIO
  ];
  
  possibleSockets.forEach(socket => {
    if (socket && socket.emit && socket.on) {
      sockets.push(socket);
    }
  });
  
  if (sockets.length === 0 && window.io) {
    // Try to find by monitoring new connections
    const originalIo = window.io;
    window.io = function(...args) {
      const socket = originalIo.apply(this, args);
      console.log('πŸ†• New Socket.io connection created');
      analyzeSocket(socket);
      return socket;
    };
    window.io.prototype = originalIo.prototype;
  }
  
  // Analyze found sockets
  sockets.forEach((socket, index) => {
    console.log(`\nπŸ“‘ Socket instance #${index + 1}`);
    analyzeSocket(socket);
  });
  
  function analyzeSocket(socket) {
    console.log(`  Connected: ${socket.connected}`);
    console.log(`  ID: ${socket.id || 'not assigned'}`);
    
    // Monitor events
    const events = new Map();
    
    // Override emit to track outgoing
    const originalEmit = socket.emit;
    socket.emit = function(event, ...args) {
      if (!events.has(event)) {
        events.set(event, { sent: 0, received: 0 });
      }
      events.get(event).sent++;
      
      console.log(`πŸ“€ Emit: ${event}`);
      if (args.length > 0 && typeof args[0] !== 'function') {
        console.log(`   Data: ${JSON.stringify(args[0]).substring(0, 100)}...`);
      }
      
      return originalEmit.apply(this, arguments);
    };
    
    // Override on to track incoming
    const originalOn = socket.on;
    socket.on = function(event, handler) {
      if (!events.has(event)) {
        events.set(event, { sent: 0, received: 0 });
      }
      
      const wrappedHandler = function(...args) {
        events.get(event).received++;
        console.log(`πŸ“¨ Received: ${event}`);
        if (args.length > 0) {
          console.log(`   Data: ${JSON.stringify(args[0]).substring(0, 100)}...`);
        }
        return handler.apply(this, args);
      };
      
      console.log(`πŸ‘‚ Listening for: ${event}`);
      return originalOn.call(this, event, wrappedHandler);
    };
    
    // Common Socket.io events to monitor
    const commonEvents = [
      'connect',
      'disconnect',
      'error',
      'reconnect',
      'message'
    ];
    
    commonEvents.forEach(event => {
      socket.on(event, (data) => {
        console.log(`🎯 ${event} event:`, data);
      });
    });
    
    // Security analysis
    console.log('\nπŸ”’ Security Analysis:');
    
    // Check transport
    if (socket.io) {
      console.log(`  Transport: ${socket.io.engine?.transport?.name || 'unknown'}`);
      
      if (window.location.protocol === 'https:' && 
          socket.io.uri && socket.io.uri.startsWith('ws://')) {
        console.log('  ⚠️ WARNING: Insecure WebSocket on HTTPS!');
      }
    }
    
    // Check authentication
    if (socket.auth || socket.io?.opts?.auth) {
      console.log('  βœ… Authentication configured');
    } else {
      console.log('  ⚠️ No authentication found');
    }
    
    // List all event listeners
    setTimeout(() => {
      console.log('\nπŸ“Š Event Summary:');
      events.forEach((stats, event) => {
        console.log(`  ${event}: ${stats.sent} sent, ${stats.received} received`);
      });
    }, 5000);
  }
}

analyzeSocketIO();

3. Server-Sent Events (SSE) Monitor

// Monitor Server-Sent Events connections
function monitorSSE() {
  console.log('\nπŸ“‘ Server-Sent Events Monitor\n');
  
  const connections = [];
  
  // Override EventSource
  const OriginalEventSource = window.EventSource;
  
  window.EventSource = function(url, config) {
    console.log(`πŸ†• New SSE connection: ${url}`);
    
    const es = new OriginalEventSource(url, config);
    const connInfo = {
      url: url,
      config: config,
      state: 'CONNECTING',
      events: new Map(),
      startTime: Date.now(),
      reconnects: 0
    };
    
    connections.push(connInfo);
    
    // Monitor connection state
    es.addEventListener('open', () => {
      connInfo.state = 'OPEN';
      console.log(`βœ… SSE connected: ${url}`);
      
      // Security check
      const sseUrl = new URL(url, window.location.origin);
      if (sseUrl.protocol === 'http:' && window.location.protocol === 'https:') {
        console.log('  ⚠️ WARNING: Insecure SSE on HTTPS page!');
      }
    });
    
    es.addEventListener('error', (e) => {
      connInfo.state = 'ERROR';
      connInfo.reconnects++;
      console.log(`❌ SSE error on ${url} (reconnect #${connInfo.reconnects})`);
    });
    
    // Override addEventListener to monitor all events
    const originalAddEventListener = es.addEventListener;
    es.addEventListener = function(type, listener, options) {
      if (type !== 'open' && type !== 'error') {
        if (!connInfo.events.has(type)) {
          connInfo.events.set(type, 0);
        }
        
        // Wrap listener to count events
        const wrappedListener = function(event) {
          connInfo.events.get(type)++;
          console.log(`πŸ“¨ SSE Event: ${type}`);
          console.log(`   Data: ${event.data?.substring(0, 100)}...`);
          
          // Check for sensitive data
          if (event.data) {
            const sensitive = /password|token|key|secret/i.test(event.data);
            if (sensitive) {
              console.log('   ⚠️ SENSITIVE DATA DETECTED!');
            }
          }
          
          return listener.apply(this, arguments);
        };
        
        console.log(`πŸ‘‚ SSE listening for: ${type}`);
        return originalAddEventListener.call(this, type, wrappedListener, options);
      }
      
      return originalAddEventListener.apply(this, arguments);
    };
    
    return es;
  };
  
  // Check for existing EventSource instances
  console.log('Checking for existing SSE connections...');
  
  // Common patterns
  const patterns = [
    window.eventSource,
    window.sse,
    window.source
  ];
  
  patterns.forEach(source => {
    if (source && source.readyState !== undefined) {
      console.log('Found existing SSE connection');
      connections.push({
        url: source.url || 'unknown',
        state: ['CONNECTING', 'OPEN', 'CLOSED'][source.readyState],
        existing: true
      });
    }
  });
  
  // Status report
  setInterval(() => {
    if (connections.length > 0) {
      console.log('\nπŸ“Š SSE Status Report');
      connections.forEach((conn, index) => {
        console.log(`\nConnection #${index + 1}: ${conn.url}`);
        console.log(`  State: ${conn.state}`);
        console.log(`  Reconnects: ${conn.reconnects}`);
        if (conn.events.size > 0) {
          console.log('  Events received:');
          conn.events.forEach((count, event) => {
            console.log(`    ${event}: ${count}`);
          });
        }
      });
    }
  }, 10000);
  
  console.log('SSE monitoring active...');
}

monitorSSE();

Real-time Security Analysis

1. Connection Security Scanner

// Analyze security of real-time connections
async function scanRealtimeSecurity() {
  console.log('\nπŸ”’ Real-time Connection Security Scan\n');
  
  const issues = [];
  
  // 1. Check for insecure WebSockets
  console.log('1️⃣ Checking WebSocket security...');
  
  // Look for ws:// on https:// pages
  if (window.location.protocol === 'https:') {
    const scripts = Array.from(document.scripts);
    const scriptContent = scripts.map(s => s.innerHTML).join(' ');
    
    if (scriptContent.includes('ws://') && !scriptContent.includes('wss://')) {
      issues.push({
        severity: 'HIGH',
        issue: 'Insecure WebSocket on HTTPS page',
        impact: 'Man-in-the-middle attacks possible',
        fix: 'Use wss:// instead of ws://'
      });
    }
  }
  
  // 2. Check for authentication
  console.log('2️⃣ Checking authentication...');
  
  // Monitor for auth tokens in URLs
  const OriginalWebSocket = window.WebSocket;
  window.WebSocket = function(url, protocols) {
    const urlObj = new URL(url);
    
    // Check for tokens in URL
    if (urlObj.searchParams.has('token') || 
        urlObj.searchParams.has('auth') ||
        urlObj.searchParams.has('key')) {
      issues.push({
        severity: 'HIGH',
        issue: 'Authentication token in WebSocket URL',
        impact: 'Tokens visible in logs and referrer headers',
        fix: 'Send auth tokens in connection headers or first message'
      });
    }
    
    return new OriginalWebSocket(url, protocols);
  };
  window.WebSocket.prototype = OriginalWebSocket.prototype;
  
  // 3. Check for origin validation
  console.log('3️⃣ Testing origin validation...');
  
  try {
    // Test WebSocket with different origin
    const testWs = new WebSocket(
      window.location.origin.replace('http', 'ws') + '/test',
      []
    );
    
    testWs.onerror = () => {
      console.log('  βœ… Origin validation appears to be working');
    };
    
    testWs.onopen = () => {
      issues.push({
        severity: 'MEDIUM',
        issue: 'WebSocket accepts connections from any origin',
        impact: 'Cross-site WebSocket hijacking possible',
        fix: 'Validate Origin header on server'
      });
      testWs.close();
    };
    
    setTimeout(() => testWs.close(), 1000);
  } catch (e) {
    // Connection failed - good
  }
  
  // 4. Check for rate limiting
  console.log('4️⃣ Testing rate limiting...');
  
  let rapidMessages = 0;
  const testRateLimit = () => {
    const ws = new WebSocket(
      window.location.origin.replace('http', 'ws') + '/test'
    );
    
    ws.onopen = () => {
      // Send many messages rapidly
      for (let i = 0; i < 100; i++) {
        try {
          ws.send(JSON.stringify({ test: i }));
          rapidMessages++;
        } catch (e) {
          break;
        }
      }
      ws.close();
    };
    
    ws.onerror = () => {};
  };
  
  // Don't actually spam the server
  console.log('  ⚠️ Rate limit test skipped (would spam server)');
  
  // 5. Check for message validation
  console.log('5️⃣ Checking message validation...');
  
  // Look for JSON parsing without try/catch
  const hasUnsafeJSONParsing = Array.from(document.scripts)
    .some(script => {
      const content = script.innerHTML;
      return content.includes('JSON.parse(') && 
             !content.includes('try') && 
             content.includes('message');
    });
  
  if (hasUnsafeJSONParsing) {
    issues.push({
      severity: 'MEDIUM',
      issue: 'Unsafe JSON parsing in message handlers',
      impact: 'Malformed messages can crash application',
      fix: 'Wrap JSON.parse in try/catch blocks'
    });
  }
  
  // Report findings
  console.log('\nπŸ“‹ Security Scan Results:');
  
  if (issues.length === 0) {
    console.log('βœ… No major security issues found');
  } else {
    console.log(`❌ Found ${issues.length} security issues:\n`);
    
    issues.sort((a, b) => {
      const severity = { HIGH: 3, MEDIUM: 2, LOW: 1 };
      return severity[b.severity] - severity[a.severity];
    }).forEach((issue, index) => {
      console.log(`${index + 1}. ${issue.severity}: ${issue.issue}`);
      console.log(`   Impact: ${issue.impact}`);
      console.log(`   Fix: ${issue.fix}\n`);
    });
  }
  
  // Best practices
  console.log('πŸ’‘ Real-time Security Best Practices:');
  console.log('1. Always use wss:// on HTTPS sites');
  console.log('2. Implement proper authentication');
  console.log('3. Validate message origin and format');
  console.log('4. Rate limit connections and messages');
  console.log('5. Implement heartbeat/timeout mechanisms');
  console.log('6. Log and monitor anomalous behavior');
  
  return issues;
}

scanRealtimeSecurity();

2. Message Pattern Analyzer

// Analyze patterns in real-time messages
class MessagePatternAnalyzer {
  constructor() {
    this.patterns = new Map();
    this.anomalies = [];
    this.startTime = Date.now();
  }
  
  analyzeMessage(type, data, connection) {
    // Get or create pattern entry
    if (!this.patterns.has(type)) {
      this.patterns.set(type, {
        count: 0,
        sizes: [],
        intervals: [],
        lastTime: Date.now(),
        samples: []
      });
    }
    
    const pattern = this.patterns.get(type);
    const now = Date.now();
    
    // Update statistics
    pattern.count++;
    pattern.intervals.push(now - pattern.lastTime);
    pattern.lastTime = now;
    
    // Analyze data
    let dataSize = 0;
    let dataStructure = null;
    
    if (typeof data === 'string') {
      dataSize = data.length;
      
      // Try to parse structure
      try {
        const parsed = JSON.parse(data);
        dataStructure = this.getStructure(parsed);
      } catch (e) {
        dataStructure = 'string';
      }
    } else if (data instanceof ArrayBuffer) {
      dataSize = data.byteLength;
      dataStructure = 'binary';
    }
    
    pattern.sizes.push(dataSize);
    
    // Store sample (first 5)
    if (pattern.samples.length < 5) {
      pattern.samples.push({
        data: data.substring ? data.substring(0, 100) : '[binary]',
        structure: dataStructure,
        timestamp: now
      });
    }
    
    // Detect anomalies
    this.detectAnomalies(type, pattern, dataSize);
  }
  
  getStructure(obj) {
    if (Array.isArray(obj)) {
      return 'array';
    }
    if (obj === null) {
      return 'null';
    }
    if (typeof obj === 'object') {
      const keys = Object.keys(obj).sort();
      return `object:${keys.join(',')}`;
    }
    return typeof obj;
  }
  
  detectAnomalies(type, pattern, currentSize) {
    // Size anomaly
    if (pattern.sizes.length > 10) {
      const avgSize = pattern.sizes.reduce((a, b) => a + b) / pattern.sizes.length;
      if (currentSize > avgSize * 5) {
        this.anomalies.push({
          type: 'size',
          message: `Unusually large ${type} message: ${currentSize} bytes (avg: ${avgSize.toFixed(0)})`
        });
      }
    }
    
    // Frequency anomaly
    if (pattern.intervals.length > 10) {
      const avgInterval = pattern.intervals.reduce((a, b) => a + b) / pattern.intervals.length;
      const lastInterval = pattern.intervals[pattern.intervals.length - 1];
      
      if (lastInterval < avgInterval / 10) {
        this.anomalies.push({
          type: 'frequency',
          message: `Rapid ${type} messages: ${lastInterval}ms interval (avg: ${avgInterval.toFixed(0)}ms)`
        });
      }
    }
  }
  
  report() {
    console.log('\nπŸ“Š Message Pattern Analysis Report');
    console.log('═'.repeat(50));
    
    const duration = (Date.now() - this.startTime) / 1000;
    console.log(`Analysis duration: ${duration.toFixed(1)}s\n`);
    
    // Pattern summary
    this.patterns.forEach((pattern, type) => {
      console.log(`πŸ“¨ Message Type: ${type}`);
      console.log(`   Count: ${pattern.count}`);
      console.log(`   Rate: ${(pattern.count / duration).toFixed(1)} msg/s`);
      
      if (pattern.sizes.length > 0) {
        const avgSize = pattern.sizes.reduce((a, b) => a + b) / pattern.sizes.length;
        const maxSize = Math.max(...pattern.sizes);
        console.log(`   Avg size: ${avgSize.toFixed(0)} bytes`);
        console.log(`   Max size: ${maxSize} bytes`);
      }
      
      if (pattern.samples.length > 0) {
        console.log('   Sample structures:');
        const structures = [...new Set(pattern.samples.map(s => s.structure))];
        structures.forEach(s => console.log(`     - ${s}`));
      }
      
      console.log('');
    });
    
    // Anomalies
    if (this.anomalies.length > 0) {
      console.log('⚠️ Anomalies Detected:');
      this.anomalies.forEach(anomaly => {
        console.log(`   - ${anomaly.message}`);
      });
    }
    
    // Security recommendations based on patterns
    console.log('\nπŸ”’ Security Recommendations:');
    
    let hasLargeMessages = false;
    let hasHighFrequency = false;
    
    this.patterns.forEach(pattern => {
      const avgSize = pattern.sizes.reduce((a, b) => a + b, 0) / pattern.sizes.length;
      if (avgSize > 10000) hasLargeMessages = true;
      
      const rate = pattern.count / duration;
      if (rate > 10) hasHighFrequency = true;
    });
    
    if (hasLargeMessages) {
      console.log('1. Implement message size limits');
      console.log('2. Consider compression for large payloads');
    }
    
    if (hasHighFrequency) {
      console.log('3. Implement rate limiting per connection');
      console.log('4. Consider message batching');
    }
    
    console.log('5. Validate all message formats');
    console.log('6. Implement connection timeouts');
  }
}

// Initialize analyzer
const messageAnalyzer = new MessagePatternAnalyzer();

// Hook into WebSocket to analyze
const OriginalWebSocket = window.WebSocket;
window.WebSocket = function(url, protocols) {
  const ws = new OriginalWebSocket(url, protocols);
  
  ws.addEventListener('message', (event) => {
    messageAnalyzer.analyzeMessage('incoming', event.data, url);
  });
  
  const originalSend = ws.send;
  ws.send = function(data) {
    messageAnalyzer.analyzeMessage('outgoing', data, url);
    return originalSend.apply(this, arguments);
  };
  
  return ws;
};

// Report after 30 seconds
setTimeout(() => messageAnalyzer.report(), 30000);

console.log('Message pattern analysis started (30s collection)...');

Complete Real-time Audit

Comprehensive Connection Assessment

// Run complete real-time connection audit
async function completeRealtimeAudit() {
  console.log('πŸ”Œ COMPLETE REAL-TIME CONNECTION AUDIT');
  console.log('═'.repeat(50));
  console.log(`URL: ${window.location.href}`);
  console.log(`Date: ${new Date().toLocaleDateString()}\n`);
  
  const audit = {
    connections: {
      websocket: 0,
      socketio: false,
      sse: 0,
      longPolling: false
    },
    security: {
      score: 100,
      issues: []
    },
    performance: {
      messageRate: 0,
      bandwidth: 0,
      reconnections: 0
    },
    recommendations: []
  };
  
  // Phase 1: Connection Detection
  console.log('πŸ“‘ PHASE 1: CONNECTION DETECTION');
  console.log('─'.repeat(40));
  
  // Check for WebSocket
  if (window.WebSocket) {
    console.log('βœ… WebSocket API available');
    
    // Monitor for 5 seconds
    let wsConnections = 0;
    const OriginalWS = window.WebSocket;
    window.WebSocket = function(url) {
      wsConnections++;
      audit.connections.websocket++;
      console.log(`  πŸ”Œ WebSocket connection: ${url}`);
      
      // Security check
      if (url.startsWith('ws://') && window.location.protocol === 'https:') {
        audit.security.issues.push('Insecure WebSocket on HTTPS');
        audit.security.score -= 20;
      }
      
      return new OriginalWS(url);
    };
    window.WebSocket.prototype = OriginalWS.prototype;
  }
  
  // Check for Socket.io
  if (window.io) {
    audit.connections.socketio = true;
    console.log('βœ… Socket.io detected');
  }
  
  // Check for EventSource (SSE)
  if (window.EventSource) {
    console.log('βœ… Server-Sent Events available');
  }
  
  // Check for long polling (XHR/fetch patterns)
  let pollCount = 0;
  const checkLongPolling = () => {
    const xhrOpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function(method, url) {
      if (method === 'GET' && url.includes('poll')) {
        pollCount++;
        if (pollCount > 3) {
          audit.connections.longPolling = true;
        }
      }
      return xhrOpen.apply(this, arguments);
    };
  };
  checkLongPolling();
  
  // Phase 2: Security Analysis
  console.log('\nπŸ”’ PHASE 2: SECURITY ANALYSIS');
  console.log('─'.repeat(40));
  
  // Check protocols
  if (window.location.protocol === 'https:') {
    console.log('βœ… Page served over HTTPS');
  } else {
    console.log('❌ Page not using HTTPS');
    audit.security.issues.push('Not using HTTPS');
    audit.security.score -= 30;
  }
  
  // Check for auth tokens in URLs
  const scripts = Array.from(document.scripts);
  const hasTokensInUrls = scripts.some(s => 
    s.innerHTML.includes('?token=') || 
    s.innerHTML.includes('&auth=')
  );
  
  if (hasTokensInUrls) {
    console.log('⚠️ Possible auth tokens in URLs');
    audit.security.issues.push('Auth tokens in URLs');
    audit.security.score -= 15;
  }
  
  // Phase 3: Performance Analysis
  console.log('\n⚑ PHASE 3: PERFORMANCE ANALYSIS');
  console.log('─'.repeat(40));
  
  // Monitor for 5 seconds
  const startMonitoring = Date.now();
  let messageCount = 0;
  let totalBytes = 0;
  
  // Override WebSocket to count messages
  if (window.WebSocket) {
    const OriginalWS = window.WebSocket;
    window.WebSocket = function(url) {
      const ws = new OriginalWS(url);
      
      ws.addEventListener('message', (e) => {
        messageCount++;
        totalBytes += e.data.length || e.data.size || 0;
      });
      
      const originalSend = ws.send;
      ws.send = function(data) {
        messageCount++;
        totalBytes += data.length || data.size || 0;
        return originalSend.apply(this, arguments);
      };
      
      return ws;
    };
    window.WebSocket.prototype = OriginalWS.prototype;
  }
  
  // Wait and calculate
  setTimeout(() => {
    const duration = (Date.now() - startMonitoring) / 1000;
    audit.performance.messageRate = (messageCount / duration).toFixed(1);
    audit.performance.bandwidth = (totalBytes / duration / 1024).toFixed(1); // KB/s
    
    console.log(`Message rate: ${audit.performance.messageRate} msg/s`);
    console.log(`Bandwidth: ${audit.performance.bandwidth} KB/s`);
    
    // Phase 4: Best Practices
    console.log('\nβœ… PHASE 4: BEST PRACTICES CHECK');
    console.log('─'.repeat(40));
    
    const practices = {
      'Secure protocol (wss://)': audit.connections.websocket === 0 || 
                                  !audit.security.issues.includes('Insecure WebSocket on HTTPS'),
      'Authentication implemented': !audit.security.issues.includes('Auth tokens in URLs'),
      'Compression enabled': true, // Would need server access to verify
      'Heartbeat/ping implemented': messageCount > 0 // Rough check
    };
    
    Object.entries(practices).forEach(([practice, implemented]) => {
      console.log(`${implemented ? 'βœ…' : '❌'} ${practice}`);
      if (!implemented) {
        audit.security.score -= 5;
      }
    });
    
    // Final Score
    audit.security.score = Math.max(0, audit.security.score);
    
    console.log('\nπŸ“Š AUDIT SUMMARY');
    console.log('═'.repeat(50));
    console.log(`Security Score: ${audit.security.score}/100`);
    console.log(`Active connections: ${audit.connections.websocket + (audit.connections.socketio ? 1 : 0)}`);
    console.log(`Message rate: ${audit.performance.messageRate} msg/s`);
    console.log(`Issues found: ${audit.security.issues.length}`);
    
    // Risk level
    let risk = 'LOW';
    if (audit.security.score < 50) risk = 'HIGH';
    else if (audit.security.score < 70) risk = 'MEDIUM';
    
    console.log(`Risk Level: ${risk}`);
    
    // Recommendations
    console.log('\nπŸ’‘ RECOMMENDATIONS:');
    
    if (audit.security.issues.includes('Insecure WebSocket on HTTPS')) {
      console.log('1. Use wss:// for all WebSocket connections');
    }
    if (audit.security.issues.includes('Auth tokens in URLs')) {
      console.log('2. Move auth tokens to headers or message payload');
    }
    if (audit.performance.messageRate > 50) {
      console.log('3. Implement message batching to reduce overhead');
    }
    if (!audit.connections.websocket && !audit.connections.socketio) {
      console.log('4. Consider WebSocket for real-time features');
    }
    console.log('5. Implement connection state recovery');
    console.log('6. Add message compression for large payloads');
    console.log('7. Monitor for connection stability');
    
  }, 5000);
  
  console.log('\nCollecting data for 5 seconds...');
  
  return audit;
}

// Run the complete audit
completeRealtimeAudit();

The Bottom Line

Real-time connections are powerful but risky:

  • Every connection is persistent - Traditional security doesn't apply
  • Messages bypass normal controls - No CORS, different auth model
  • Performance compounds quickly - Message storms crash servers
  • Debugging is harder - Async, bidirectional, binary protocols
  • Security often an afterthought - Focus on functionality over protection

Monitor every connection. Validate every message. Secure every transport. Real-time means real risk.


Monitor real-time connections instantly: Fusebox tracks WebSocket, Socket.io, and SSE connections, analyzes message patterns, and detects security issues while you browse. Secure your real-time data flows. $29 one-time purchase.