servidor - websocket c# javascript example
¿Para qué sirve Sec-WebSocket-Key? (3)
En la sección 1.3 "Abrir el apretón de manos" del borrador-ietf-hybi-thewebsocketprotocol-17 , describe Sec-WebSocket-Key
siguiente manera:
Para demostrar que se recibió el apretón de manos, el servidor debe tomar dos piezas de información y combinarlas para formar una respuesta. La primera información proviene de | Sec-WebSocket-Key | campo de encabezado en el protocolo de enlace del cliente:
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Para este campo de encabezado, el servidor debe tomar el valor (como presente en el campo del encabezado, por ejemplo, la versión codificada en base64 [RFC4648] menos cualquier espacio en blanco inicial y final) y concatenarlo con el identificador único global (GUID, [RFC4122] ]) "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" en forma de cadena, que es poco probable que sea utilizado por los puntos finales de la red que no entienden el protocolo WebSocket. Un hash SHA-1 (160 bits), codificado en base64 (consulte la Sección 4 de [RFC4648]), de esta concatenación se devuelve en el protocolo de enlace del servidor [FIPS.180-2.2002].
Aquí está lo que no puedo entender: ¿por qué no simplemente devolver el código 101? Si el uso apropiado de Sec-WebSocket-Key
es por seguridad, o para demostrar que pueden manejar las solicitudes de websocket, entonces cualquier servidor podría devolver la clave esperada si quisieran, y pretender que son un servidor WebSocket.
De acuerdo con el estándar RFC 6455 Websocket
.. the server has to prove to the client that it received the
client''s WebSocket handshake, so that the server doesn''t accept
connections that are not WebSocket connections. This prevents an
attacker from tricking a WebSocket server by sending it carefully
crafted packets using XMLHttpRequest [XMLHttpRequest] or a form
submission.
...
For this header field, the server has to take the value (as present
in the header field, e.g., the base64-encoded [RFC4648] version minus
any leading and trailing whitespace) and concatenate this with the
Globally Unique Identifier (GUID, [RFC4122]) "258EAFA5-E914-47DA-
95CA-C5AB0DC85B11" in string form, which is unlikely to be used by
network endpoints that do not understand the WebSocket Protocol.
The |Sec-WebSocket-Key| header field is used in the WebSocket opening
handshake. It is sent from the client to the server to provide part
of the information used by the server to prove that it received a
valid WebSocket opening handshake. This helps ensure that the server
does not accept connections from non-WebSocket clients (e.g., HTTP
clients) that are being abused to send data to unsuspecting WebSocket
servers.
Entonces, como el valor del GUID se especifica en el estándar, es poco probable (es posible, con muy poca probabilidad) que el servidor que no conoce Websockets lo use. No proporciona ningún tipo de seguridad (websockets seguros - wss: // - does), solo garantiza que el servidor comprenda el protocolo de websockets.
En realidad, como has mencionado, si conoces los websockets (eso es lo que se debe comprobar), puedes pretender ser un servidor websocket enviando la respuesta correcta. Pero luego, si no actúa correctamente (por ejemplo, forma marcos correctamente), se considerará una violación del protocolo. En realidad, puede escribir un servidor websocket que sea incorrecto, pero no tendrá mucho uso.
Y otro propósito es evitar que los clientes soliciten accidentalmente la actualización de websockets sin esperarlo (por ejemplo, agregando los encabezados correspondientes manualmente y luego esperando algo más). Sec-WebSocket-Key y otros encabezados relacionados están prohibidos para establecerse mediante el método setRequestHeader
en los navegadores.
Me inclino a estar de acuerdo.
Nada de importancia cambiaría si el cliente ignorase el valor del encabezado Sec-WebSocket-Accept.
¿Por qué? Debido a que el servidor no está probando nada haciendo este cálculo (aparte de que tiene el código para hacer el cálculo). Casi lo único que descarta es un servidor que simplemente responda con una respuesta enlatada.
El intercambio de encabezados (por ejemplo, con valores fijos de ''clave'' y ''aceptar'') ya es suficiente para descartar cualquier conexión accidental con algo que al menos no intente ser un servidor WebSocket; y si lo está intentando, el requisito de que haga este cálculo no es un impedimento para su éxito.
El RFC afirma:
"... el servidor debe demostrarle al cliente que recibió el protocolo de enlace WebSocket del cliente, de modo que el servidor no acepte conexiones que no sean conexiones WebSocket".
y:
"Esto ayuda a garantizar que el servidor no acepte conexiones de clientes que no sean de WebSocket ..."
Ninguna de estas afirmaciones tiene sentido. El servidor nunca es el que rechaza la conexión porque es el que está computando el hash, no el que lo está verificando.
Este tipo de intercambio tendría algún sentido si el GUID mágico no fuera fijo, sino que fuera un secreto compartido entre el cliente y el servidor. En ese caso, el intercambio permitiría al servidor probar al cliente que tenía el secreto compartido sin revelarlo.
Sobre todo para el almacenamiento en memoria caché.
Imagine un servidor de proxy inverso transparente que vea el tráfico HTTP pasar. Si no comprende WS, podría almacenar en caché por error un saludo de WS y responder con un 101 inútil al próximo cliente.
Usar un nonce (la clave) y requerir una respuesta de desafío básica bastante específica para WS asegura que el servidor realmente entendió que se trataba de un handshake de WS y, a su vez, le dice al cliente que el servidor realmente estará escuchando en el puerto. Un proxy inverso en caché nunca implementaría esa lógica hash "por error".