WebSocket es un protocolo de comunicaciones informáticas que proporciona canales de comunicación bidireccionales simultáneos a través de una única conexión de Protocolo de control de transmisión (TCP). El protocolo WebSocket fue estandarizado por el IETF como RFC 6455 en 2011. La especificación actual que permite que las aplicaciones web utilicen este protocolo se conoce como WebSockets . [1] Es un estándar de vida mantenido por WHATWG y sucesor de la API WebSocket del W3C . [2]
WebSocket es distinto de HTTP que se utiliza para servir a la mayoría de las páginas web. Aunque son diferentes, RFC 6455 establece que WebSocket "está diseñado para funcionar a través de los puertos HTTP 443 y 80, así como para admitir servidores proxy e intermediarios HTTP", lo que lo hace compatible con HTTP. Para lograr compatibilidad, el protocolo de enlace WebSocket utiliza el encabezado de actualización HTTP [3] para cambiar del protocolo HTTP al protocolo WebSocket.
El protocolo WebSocket permite la interacción full-duplex entre un navegador web (u otra aplicación cliente ) y un servidor web con una sobrecarga menor que las alternativas half-duplex como el sondeo HTTP , lo que facilita la transferencia de datos en tiempo real desde y hacia el servidor. Esto es posible proporcionando una forma estandarizada para que el servidor envíe contenido al cliente sin que éste lo solicite primero, y permitiendo que los mensajes se transmitan de un lado a otro mientras se mantiene la conexión abierta. De esta manera, puede tener lugar una conversación bidireccional entre el cliente y el servidor. Las comunicaciones suelen realizarse a través del puerto TCP número 443 (u 80 en el caso de conexiones no seguras), lo que resulta beneficioso para entornos que bloquean conexiones a Internet no web mediante un firewall . Además, WebSocket permite flujos de mensajes además de TCP. TCP por sí solo se ocupa de flujos de bytes sin un concepto inherente de mensaje. Se han logrado comunicaciones bidireccionales similares entre navegador y servidor de formas no estandarizadas utilizando tecnologías provisionales como Comet o Adobe Flash Player . [4]
La mayoría de los navegadores admiten el protocolo, incluidos Google Chrome , Firefox , Microsoft Edge , Internet Explorer , Safari y Opera . [5]
La especificación del protocolo WebSocket define ws
(WebSocket) y wss
(WebSocket Secure) como dos nuevos esquemas de identificador uniforme de recursos (URI) [6] que se utilizan para conexiones cifradas y no cifradas, respectivamente. Aparte del nombre del esquema y el fragmento (es decir, #
no se admite), el resto de los componentes de URI están definidos para utilizar la sintaxis genérica de URI . [7]
WebSocket fue mencionado por primera vez como TCPConnection en la especificación HTML5 , como marcador de posición para una API de socket basada en TCP. [8] En junio de 2008, Michael Carter dirigió una serie de discusiones que dieron como resultado la primera versión del protocolo conocido como WebSocket. [9] Antes de WebSocket, la comunicación full-duplex del puerto 80 era posible mediante canales Comet ; sin embargo, la implementación de Comet no es trivial y, debido al protocolo de enlace TCP y la sobrecarga del encabezado HTTP, es ineficiente para mensajes pequeños. El protocolo WebSocket pretende solucionar estos problemas sin comprometer las suposiciones de seguridad de la web. El nombre "WebSocket" fue acuñado por Ian Hickson y Michael Carter poco después a través de la colaboración en la sala de chat IRC #whatwg, [10] y posteriormente Ian Hickson lo escribió para su inclusión en la especificación HTML5. En diciembre de 2009, Google Chrome 4 fue el primer navegador que ofreció soporte completo para el estándar, con WebSocket habilitado de forma predeterminada. [11] Posteriormente, el desarrollo del protocolo WebSocket se trasladó del grupo W3C y WHATWG al IETF en febrero de 2010, y se redactó para dos revisiones bajo la dirección de Ian Hickson. [12]
Después de que el protocolo se envió y se habilitó de forma predeterminada en varios navegadores, el RFC 6455 se finalizó bajo Ian Fette en diciembre de 2011.
RFC 7692 introdujo la extensión de compresión a WebSocket utilizando el algoritmo DEFLATE por mensaje.
Se implementa una versión segura del protocolo WebSocket en Firefox 6, [13] Safari 6, Google Chrome 14, [14] Opera 12.10 e Internet Explorer 10. [15] Un informe detallado del conjunto de pruebas de protocolo [16] enumera la conformidad de esos navegadores a aspectos específicos del protocolo.
Se implementó una versión más antigua y menos segura del protocolo en Opera 11 y Safari 5, así como en la versión móvil de Safari en iOS 4.2 . [17] El navegador BlackBerry en OS7 implementa WebSockets. [18] Debido a vulnerabilidades, se deshabilitó en Firefox 4 y 5, [19] y Opera 11. [20] Utilizando herramientas de desarrollo del navegador, los desarrolladores pueden inspeccionar el protocolo de enlace de WebSocket, así como los marcos de WebSocket. [21]
// Crea un nuevo objeto WebSocket con un URI de wss como parámetro const socket = new WebSocket ( 'wss://game.example.com/ws/updates' ); // Se activa cuando se abre una conexión con un socket WebSocket . onopen = function () { setInterval ( function () { if ( socket . bufferedAmount == 0 ) socket . send ( getUpdateData ()); }, 50 ); }; // Se activa cuando se reciben datos a través de un socket WebSocket . onmessage = función ( evento ) { handleUpdateData ( evento . datos ); }; // Se activa cuando se cierra una conexión con un socket WebSocket . onclose = función ( evento ) { onSocketClose ( evento ); }; // Se activa cuando se cierra una conexión con un WebSocket debido a un error en el socket . onerror = función ( evento ) { onSocketError ( evento ); };
Nginx ha admitido WebSockets desde 2013, implementado en la versión 1.3.13 [30] y actúa como proxy inverso y equilibrador de carga de aplicaciones WebSocket. [31]
Apache HTTP Server admite WebSockets desde julio de 2013, implementado en la versión 2.4.5 [32] [33]
Internet Information Services agregó soporte para WebSockets en la versión 8 que se lanzó con Windows Server 2012 . [34]
lighttpd admite WebSockets desde 2017, implementado en la versión 1.4.46. [35] lighttpd mod_proxy puede actuar como proxy inverso y equilibrador de carga de aplicaciones WebSocket. lighttpd mod_wstunnel puede construir túneles WebSocket para transmitir datos arbitrarios, incluso en formato JSON , a una aplicación backend.
Para establecer una conexión WebSocket, el cliente envía una solicitud de protocolo de enlace WebSocket, para la cual el servidor devuelve una respuesta de protocolo de enlace WebSocket, como se muestra en el siguiente ejemplo. [36]
Solicitud del cliente (al igual que en HTTP , cada línea termina con \r\n
y debe haber una línea en blanco adicional al final):
GET /chat HTTP / 1.1 Host : server.example.com Actualización : websocket Conexión : Actualización Sec-WebSocket-Key : x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol : chat, superchat Sec-WebSocket-Version : 13 Origen : http:// ejemplo.com
Respuesta del servidor:
HTTP / 1.1 101 Protocolos de conmutación Actualización : Conexión websocket : Actualización Sec-WebSocket-Accept : HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol : chat
El protocolo de enlace comienza con una solicitud/respuesta HTTP, lo que permite a los servidores manejar conexiones HTTP y conexiones WebSocket en el mismo puerto. Una vez establecida la conexión, la comunicación cambia a un protocolo binario bidireccional que no se ajusta al protocolo HTTP.
Además de Upgrade
los encabezados, el cliente envía un Sec-WebSocket-Key
encabezado que contiene bytes aleatorios codificados en base64 y el servidor responde con un hash de la clave en el Sec-WebSocket-Accept
encabezado. Esto tiene como objetivo evitar que un proxy de caché vuelva a enviar una conversación WebSocket anterior [37] y no proporciona autenticación, privacidad o integridad. La función hash agrega la cadena fija (un UUID ) al valor del encabezado (que no está decodificado desde base64), aplica la función hash SHA-1 y codifica el resultado usando base64. [38]258EAFA5-E914-47DA-95CA-C5AB0DC85B11
Sec-WebSocket-Key
El RFC6455 requiere que la clave DEBE ser un nonce que consista en un valor de 16 bytes seleccionado aleatoriamente que haya sido codificado en base64, [39] es decir, 24 bytes en base64 (con los dos últimos bytes como ==
). Aunque algunos servidores HTTP relajados permiten la presentación de claves más cortas, muchos servidores HTTP modernos rechazarán la solicitud con el error "encabezado Sec-WebSocket-Key no válido".
Una vez establecida la conexión, el cliente y el servidor pueden enviar datos de WebSocket o marcos de texto de un lado a otro en modo full-duplex . Los datos están mínimamente enmarcados, con un pequeño encabezado seguido de una carga útil . [40] Las transmisiones WebSocket se describen como "mensajes", donde un solo mensaje puede dividirse opcionalmente en varias tramas de datos. Esto puede permitir el envío de mensajes donde los datos iniciales están disponibles pero se desconoce la longitud completa del mensaje (envía un marco de datos tras otro hasta que se llega al final y se confirma con el bit FIN).
Con extensiones del protocolo, esto también se puede utilizar para multiplexar varios flujos simultáneamente (por ejemplo, para evitar monopolizar el uso de un socket para una única carga útil grande). [41]
Los datos de carga enviados desde el cliente deben estar enmascarados por la clave de enmascaramiento. La clave de enmascaramiento es un valor aleatorio de 4 bytes elegido por el cliente y debe ser impredecible. La imprevisibilidad de la clave de enmascaramiento es esencial para evitar que aplicaciones maliciosas seleccionen los bytes que ya aparecen. [ se necesita aclaración ] Se aplica el siguiente algoritmo para enmascarar los datos de la carga útil.
j = yo MOD 4Octeto-transformado[i] = octeto-original[i] XOR octeto-clave-de-enmascaramiento[j]
A diferencia de las solicitudes HTTP normales entre dominios, las solicitudes WebSocket no están restringidas por la política del mismo origen . Por lo tanto, los servidores WebSocket deben validar el encabezado "Origin" con los orígenes esperados durante el establecimiento de la conexión, para evitar ataques de secuestro de WebSocket entre sitios (similar a la falsificación de solicitudes entre sitios ), lo que podría ser posible cuando la conexión se autentica con cookies o HTTP. autenticación. Es mejor utilizar tokens o mecanismos de protección similares para autenticar la conexión WebSocket cuando se transfieren datos confidenciales (privados) a través de WebSocket. [42] Un ejemplo vivo de vulnerabilidad se vio en 2020 en la forma de Cable Haunt .
Las implementaciones del cliente del protocolo WebSocket intentan detectar si el agente de usuario está configurado para usar un proxy cuando se conecta al host y al puerto de destino y, si lo está, usa el método HTTP CONNECT para configurar un túnel persistente.
Si bien el protocolo WebSocket en sí desconoce los servidores proxy y los firewalls, presenta un protocolo de enlace compatible con HTTP, lo que permite a los servidores HTTP compartir sus puertos HTTP y HTTPS predeterminados (80 y 443 respectivamente) con una puerta de enlace o servidor WebSocket. El protocolo WebSocket define un prefijo ws:// y wss:// para indicar una conexión WebSocket y WebSocket Secure, respectivamente. Ambos esquemas utilizan un mecanismo de actualización HTTP para actualizar al protocolo WebSocket. Algunos servidores proxy son transparentes y funcionan bien con WebSocket; otros impedirán que WebSocket funcione correctamente, provocando que falle la conexión. En algunos casos, es posible que se requiera una configuración adicional del servidor proxy y es posible que sea necesario actualizar ciertos servidores proxy para que admitan WebSocket.
Si el tráfico WebSocket no cifrado fluye a través de un servidor proxy explícito o transparente sin soporte WebSockets, es probable que la conexión falle. [43]
Si se utiliza una conexión WebSocket cifrada, el uso de Transport Layer Security (TLS) en la conexión WebSocket Secure garantiza que HTTP CONNECT
se emita un comando cuando el navegador esté configurado para usar un servidor proxy explícito. Esto configura un túnel, que proporciona comunicación TCP de extremo a extremo de bajo nivel a través del proxy HTTP, entre el cliente WebSocket Secure y el servidor WebSocket. En el caso de servidores proxy transparentes, el navegador no reconoce el servidor proxy, por lo que no HTTP CONNECT
se envía. Sin embargo, dado que el tráfico por cable está cifrado, los servidores proxy transparentes intermedios pueden simplemente permitir el paso del tráfico cifrado, por lo que hay muchas más posibilidades de que la conexión WebSocket tenga éxito si se utiliza WebSocket Secure. El uso de cifrado no está exento de costos de recursos, pero a menudo proporciona la tasa de éxito más alta, ya que sería viajar a través de un túnel seguro.
Un borrador de mediados de 2010 (versión hixie-76) rompió la compatibilidad con servidores proxy inversos y puertas de enlace al incluir ocho bytes de datos clave después de los encabezados, pero no anunciar esos datos en un Content-Length: 8
encabezado. [44] Estos datos no fueron enviados por todos los intermediarios, lo que podría provocar una falla en el protocolo. Los borradores más recientes (por ejemplo, hybi-09 [45] ) colocan los datos clave en un Sec-WebSocket-Key
encabezado, resolviendo este problema.
Las conexiones TCP requieren un "cliente" y un "servidor".
Flash Player puede crear sockets de cliente.
El cálculo [...] está destinado a evitar que un intermediario de almacenamiento en caché proporcione a un cliente WS una respuesta del servidor WS en caché sin una interacción real con el servidor WS.