Errores Comunes en WebSockets en Sitios HTTPS y Soluciones

Dado que HTTPS se basa en SSL para verificar la identidad del servidor mediante certificados y cifrar la comunicación entre el navegador y el servidor, el navegador puede bloquear ciertos recursos que no utilizan SSL cuando se usan en sitios HTTPS. Por ejemplo, al intentar conectar a un servidor WebSocket mediante ws:// o incluir archivos JavaScript desde http://, se pueden producir errores. A continuación, se describen los errores comunes al conectar a servidores WebSocket y sus soluciones.

Al utilizar ws:// para conectar con un servidor WebSocket en un sitio HTTPS, pueden aparecer errores similares a estos:

Contenido Mixto: La página '' se cargó mediante HTTPS, pero intentó conectarse al endpoint WebSocket inseguro 'ws://'. Esta solicitud ha sido bloqueada; este endpoint debe estar disponible mediante WSS. (anonymous) Uncaught DOMException: No se pudo construir 'WebSocket': No se puede iniciar una conexión WebSocket insegura desde una página cargada a través de HTTPS.

Si el navegador no bloqueara estas conexiones, solo sería posible llamar a recursos SSL desde un sitio HTTPS. A continuación, se presenten las soluciones:

Solución 1: Proxy de WebSocket mediante Nginx

Si el sitio HTTPS utiliza un servidor Nginx (el proceso es similar en otros servidores), se puede configurar un proxy para el servicio WebSocket. A continuación, se detalla la configuración:

# Primero, modificar la dirección WebSocket en el cliente para usar wss://url_del_proxy (el proxy debe soportar https)
var socket = new WebSocket("wss://www.ejemplo-proxy.com/websocket");

# En el archivo de configuración de Nginx del servidor proxy, añadir las siguientes directivas dentro del bloque server:
location /websocket/ {
    proxy_pass http://servidor_backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

# Añadir en la sección http:
upstream servidor_backend{
   ip_servidor_websocket:puerto;
}

De esta forma, el cliente solicita a wss://servidor, y Nginx actúa como proxy hacia el servidor WebSocket real que no soporta SSL.

Solución 2: Implementación SSL directa en el serviodr WebSocket

Se puede agregar un certificado SSL directamente al servidor WebSocket para permitir conexiones wss:// directas. A continuación, se muestra un ejemplo con Swoole (el proceso es similar en otros servidores):

// Para usar SSL con Swoole, es necesario compilar con la opción --enable-openssl
$wservidor = new Swoole\WebSocket\Server("0.0.0.0", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$wservidor->set(
    [
      'ssl_cert_file' => 'ruta/certificado.pem',
       'ssl_key_file' => '/ruta/privada/clave.key',
    ]
);
$wservidor->on('open', function (Swoole\WebSocket\Server $wservidor, $peticion) {
    echo "servidor: handshake exitoso con fd{$peticion->fd}\n";
});

$wservidor->on('message', function (Swoole\WebSocket\Server $wservidor, $marco) {
    echo "recibido desde {$marco->fd}:{$marco->datos},opcode:{$marco->opcode},fin:{$marco->fin}\n";
    $wservidor->push($marco->fd, "respuesta del servidor");
});

$wservidor->on('close', function ($wservidor, $identificador) {
    echo "cliente {$identificador} desconectado\n";
});

$wservidor->start();

Etiquetas: HTTPS WebSocket SSL Nginx Swoole

Publicado el 7-12 00:27