Refuerzo del servidor WebSocket en sgcWebSockets

· Componentes

Un servidor WebSocket expuesto a la internet pública es un objetivo tentador. El protocolo no tiene un límite de tamaño de mensaje integrado, por lo que una sola conexión puede intentar derribar todo el proceso con un único frame manipulado, y el handshake de actualización es un lugar fácil para sondear validaciones descuidadas. La última versión de sgcWebSockets incorpora un conjunto de protecciones que cierran estas puertas de forma predeterminada, de modo que tu servidor sigue en pie incluso bajo tráfico hostil.

Todo lo que se describe a continuación se aplica a los tres servidores WebSocket: TsgcWebSocketServer, TsgcWebSocketHTTPServer y el TsgcWebSocketServer_HTTPAPI basado en http.sys. La edición .NET hereda las mismas protecciones, porque se ejecuta sobre la misma biblioteca nativa.

Un único límite que detiene tres ataques de memoria

La incorporación principal es una sola propiedad, MaxMessageSize, que limita el tamaño máximo que puede tener un mensaje entrante. Su valor predeterminado es 64 MB, que resulta generoso para casi cualquier aplicación, y puedes subirlo o bajarlo, o asignarle 0 para desactivar el límite.

Esa única propiedad protege contra tres técnicas distintas de agotamiento de memoria que terminan todas de la misma manera, con el servidor sin RAM:

En todos los casos la conexión se cierra limpiamente con el close code 1009 de WebSocket (Message Too Big), y la memoria del servidor nunca supera el tope.

oServer := TsgcWebSocketServer.Create(nil);
oServer.Port := 80;
// accept messages up to 16 MB, reject anything larger with close 1009
oServer.MaxMessageSize := 16 * 1024 * 1024;
oServer.Active := True;

Análisis seguro de la longitud del frame

Los frames WebSocket pueden llevar un campo de longitud de 64-bit. Según RFC 6455, el bit más significativo de ese campo debe ser cero. sgcWebSockets ahora rechaza un frame cuya longitud de 64-bit tenga el bit alto activado en lugar de confiar en él, de modo que el límite de tamaño anterior no pueda eludirse con un entero que provoque un desbordamiento. Esta comprobación está siempre activa y no depende de MaxMessageSize.

Handshakes más estrictos

Dos nuevas opciones dentro de SecurityOptions refuerzan la propia actualización de WebSocket, y ambas están habilitadas de forma predeterminada.

EnforceWebSocketVersion responde a cualquier handshake que solicite una versión distinta de 13 con 426 Upgrade Required y una cabecera Sec-WebSocket-Version: 13, en lugar de completar la actualización. ValidateWebSocketKey rechaza, con 400 Bad Request, cualquier handshake cuya Sec-WebSocket-Key falte o no sea un nonce base64 válido de 16 bytes. Ambas comprobaciones se aplican solo a la ruta RFC 6455, por lo que los clientes antiguos que usan especificaciones heredadas no se ven afectados.

oServer := TsgcWebSocketServer.Create(nil);
oServer.SecurityOptions.EnforceWebSocketVersion := True;  // 426 on a wrong version
oServer.SecurityOptions.ValidateWebSocketKey := True;     // 400 on a malformed key
// lock the server to your own site while you are at it
oServer.SecurityOptions.OriginsAllowed := 'https://app.example.com';
oServer.Active := True;

Cómo encaja con el firewall

Estas protecciones residen en la capa de protocolo, dentro del analizador de frames, que es exactamente donde ocurren los ataques de memoria. Esa es la parte que los componentes Firewall y RateLimiter no pueden alcanzar, porque ven un mensaje solo después de que ha sido decodificado. Las dos capas se complementan: sigue usando el firewall y el limitador de tasa para el filtrado de IP, los límites de tasa de conexión y de mensajes y la política de origen, y deja que los nuevos límites integrados protejan el propio analizador. Para un servidor público recomendamos establecer MaxMessageSize en tu máximo real, fijar OriginsAllowed a tu front end y limitar MaxConnections.

Actualización

Las nuevas protecciones se activan en cuanto actualizas, con valores predeterminados seguros, por lo que la mayoría de los servidores obtienen el refuerzo de memoria y handshake sin un solo cambio de código. Si tu aplicación intercambia legítimamente mensajes mayores de 64 MB, sube MaxMessageSize en consecuencia. El código de cliente existente no se ve afectado.

Actualiza desde la página de descarga de sgcWebSockets, u obtenlo a través de GetIt o de tu cuenta registrada.

¿Preguntas, comentarios o ayuda con la migración? Ponte en contacto, recibirás respuesta de las personas que escribieron el código.