mediumCWE-770

Inundacion WebSocket (Sin Rate Limit)

Un servidor WebSocket sin rate limiting de mensajes permite que un solo cliente envie miles de mensajes por segundo, agotando recursos del servidor, degradando el rendimiento para todos los usuarios y potencialmente causando denegacion de servicio.

Cómo Funciona

Las conexiones WebSocket son persistentes y bidireccionales, lo que significa que un cliente puede enviar mensajes a cualquier velocidad sin necesidad de establecer nuevas conexiones. A diferencia de los endpoints HTTP donde cada request tiene overhead de conexion, los mensajes WebSocket son extremadamente ligeros. Sin rate limiting, un solo cliente malicioso puede inundar el servidor con miles de mensajes por segundo. Si cada mensaje dispara procesamiento del lado del servidor (consultas a base de datos, broadcasts a otros clientes, llamadas API), el CPU, memoria e I/O del servidor se agotan. Esto degrada el rendimiento para todos los usuarios conectados y puede crashear el servidor completamente. El ataque es trivial de ejecutar: un simple loop de JavaScript enviando mensajes tan rapido como sea posible es suficiente para abrumar la mayoria de servidores WebSocket sin proteccion.

Código Vulnerable
// BAD: no rate limiting on WebSocket messages
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });

server.on('connection', (ws) => {
  ws.on('message', async (data) => {
    const msg = JSON.parse(data);
    // Every message triggers a database write and broadcast
    await db.insert('messages', msg);
    server.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(JSON.stringify(msg)); // broadcast to all
      }
    });
    // Attacker sends 10,000 msgs/sec -> 10,000 DB writes + broadcasts/sec
  });
});
Código Seguro
// GOOD: rate limiting with token bucket per connection
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });

function createRateLimiter(maxTokens, refillRate) {
  let tokens = maxTokens;
  setInterval(() => { tokens = Math.min(maxTokens, tokens + refillRate); }, 1000);
  return () => { if (tokens > 0) { tokens--; return true; } return false; };
}

server.on('connection', (ws) => {
  const allowMessage = createRateLimiter(10, 5); // 10 burst, 5/sec refill
  let warnings = 0;
  ws.on('message', async (data) => {
    if (!allowMessage()) {
      warnings++;
      if (warnings > 3) { ws.close(1008, 'Rate limit exceeded'); return; }
      ws.send(JSON.stringify({ error: 'Too many messages, slow down' }));
      return;
    }
    const msg = JSON.parse(data);
    await db.insert('messages', msg);
    broadcast(server, msg);
  });
});

Ejemplo Real

En 2020, investigadores demostraron ataques de inundacion WebSocket contra varias plataformas populares de chat en tiempo real construidas con Socket.io, mostrando que una sola conexion podia degradar el servicio para miles de usuarios concurrentes. Los ataques explotaron la falta de rate limiting por conexion. Un caso notable involucro una plataforma de gaming donde atacantes inundaron el servidor WebSocket para causar lag y obtener ventaja competitiva, afectando a miles de jugadores durante horas pico.

Cómo Prevenirlo

  • Implementa rate limiting por conexion usando un algoritmo de token bucket o ventana deslizante que limite los mensajes a una velocidad razonable (ej. 10-50/segundo)
  • Configura limites de tamano maximo de mensaje en el servidor WebSocket para prevenir ataques de payload grande (usa la opcion maxPayload en la libreria ws)
  • Desconecta clientes que repetidamente excedan los limites de rate con un sistema de advertencias (advertir, luego cerrar con codigo 1008)
  • Monitorea conexiones WebSocket buscando tasas de mensajes anomalas e implementa limites de conexion a nivel de servidor para limitar el total de conexiones WebSocket concurrentes

Tecnologías Afectadas

Node.jsPythonGo

Data Hogo detecta esta vulnerabilidad automáticamente.

Escanea Tu Repo Gratis

Vulnerabilidades Relacionadas