micropython / micropython-lib

Core Python libraries ported to MicroPython

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

aiohttp sends Sec-WebSocket-Key with in wrong with b'' envelope

wohltat opened this issue · comments

@Carglglz
During the handshake the Sec-WebSocket-Key is send undecoded which results in it being sent with an additional b'' (like b'tb4IfqY2SEcIEy0pv0opLQ==').

If the line:

headers["Sec-WebSocket-Key"] = key

is changed to the following it doesn't cause an error anymore:

headers["Sec-WebSocket-Key"] = key.decode()

I used a python-websocket Server for testing which seems to make more sense than the other options as a servers, since it claim to be more strickly following the RFC6455 specification and offers informative error logging.

Here is the server error log of the handshake:

= connection is CONNECTING
< GET / HTTP/1.1
< Origin: https://192.168.178.123:4443
< Connection: Upgrade
< Sec-WebSocket-Key: b'tb4IfqY2SEcIEy0pv0opLQ=='
< Host: 192.168.178.123:4443
< Upgrade: websocket
< Sec-WebSocket-Version: 13
s_w_key="b'tb4IfqY2SEcIEy0pv0opLQ=='"
! invalid handshake
Traceback (most recent call last):
  File "/home/username/tls-test/venv/lib/python3.11/site-packages/websockets/legacy/handshake.py", line 86, in check_request
    raw_key = base64.b64decode(s_w_key.encode(), validate=True)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/base64.py", line 88, in b64decode
    return binascii.a2b_base64(s, strict_mode=validate)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
binascii.Error: Only base64 data is allowed

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/username/tls-test/venv/lib/python3.11/site-packages/websockets/legacy/server.py", line 167, in handler
    await self.handshake(
  File "/home/username/tls-test/venv/lib/python3.11/site-packages/websockets/legacy/server.py", line 609, in handshake
    key = check_request(request_headers)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/username/tls-test/venv/lib/python3.11/site-packages/websockets/legacy/handshake.py", line 88, in check_request
    raise InvalidHeaderValue("Sec-WebSocket-Key", s_w_key) from exc
websockets.exceptions.InvalidHeaderValue: invalid Sec-WebSocket-Key header: b'tb4IfqY2SEcIEy0pv0opLQ=='
> HTTP/1.1 400 Bad Request
> Date: Tue, 07 May 2024 00:14:16 GMT
> Server: Python/3.11 websockets/12.0
> Content-Length: 102
> Content-Type: text/plain
> Connection: close
> [body] (102 bytes)
connection rejected (400 Bad Request)
x closing TCP connection
! timed out waiting for TCP close
x aborting TCP connection
= connection is CLOSED
connection closed

After the change the connection works as expected. Strangely two other servers i've tested connected despite of this bug. After the code change they also still connect as to be expected.

Here is the server code:

#!/usr/bin/env python

import asyncio
import pathlib
import ssl
import websockets
import logging

logging.basicConfig(
    format="%(message)s",
    level=logging.DEBUG,
)

async def hello(websocket):
    while True:
        msg = await websocket.recv()
        print(f"{msg}")
        # await websocket.send(msg)

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ssl_cert = "cert.pem"
ssl_key = "key.pem"
ssl_context.load_cert_chain(ssl_cert, ssl_key)

async def main():
    async with websockets.serve(hello, "0.0.0.0", 4443, ssl=ssl_context):
        await asyncio.Future()  # run forever

if __name__ == "__main__":
    asyncio.run(main())

@wohltat yes this is known see #846