crossbario / crossbar

Crossbar.io - WAMP application router
https://crossbar.io/
Other
2.05k stars 274 forks source link

Crossbar can't identify cookie if there is JSON in request header (Cookie Authentication method) #1924

Closed yankos closed 2 years ago

yankos commented 2 years ago

Crossbar version:

    :::::::::::::::::
          :::::          _____                      __
    :::::   :   :::::   / ___/____ ___   ___  ___  / /  ___ _ ____
    :::::::   :::::::  / /__ / __// _ \ (_-< (_-< / _ \/ _ `// __/
    :::::   :   :::::  \___//_/   \___//___//___//_.__/\_,_//_/
          :::::
    :::::::::::::::::   Crossbar v21.3.1

    Copyright (c) 2013-2021 Crossbar.io Technologies GmbH, licensed under AGPL 3.0.

 Crossbar.io        : 21.3.1
   txaio            : 21.2.1
   Autobahn         : 21.3.1
     UTF8 Validator : autobahn
     XOR Masker     : autobahn
     JSON Codec     : stdlib
     MsgPack Codec  : umsgpack-2.7.1
     CBOR Codec     : cbor-1.0.0
     UBJSON Codec   : ubjson-0.16.1
     FlatBuffers    : flatbuffers-2.0
   Twisted          : 21.7.0-EPollReactor
   LMDB             : 1.2.1/lmdb-0.9.29
   Python           : 3.7.10/PyPy-7.3.5
   PIP              : 21.3.1
 Frozen executable  : no
 Operating system   : Linux-5.4.0-89-generic-x86_64-with-debian-bullseye-sid
 Host machine       : x86_64
 Release key        : RWT906S6dtgOY3NZrHd3uFtXpAPFUc6+bdpADYJRJi4daUaCT5U/0OrO

Steps to reproduce:

Make the Cookie Authentication with Google's g_state cookie: g_state={"i_l":0} Python can't parse cookies if g_state cookie is present and because of this creates new csid cookie every time. Google sets g_state cookie for "One Tap sign-in".

Output:

[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] connection accepted from peer tcp4:192.168.1.5:56973
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] Connection made to tcp4:192.168.1.5:56973
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] received HTTP request:

b'GET /ws HTTP/1.1\r\nHost: test.dev:8084\r\nConnection: Upgrade\r\nPragma: no-cache\r\nCache-Control: no-cache\r\nUser-Agent: ...Chrome/96.0.4664.93...\r\nUpgrade: websocket\r\nOrigin: https://test.dev:8080\r\nSec-WebSocket-Version: 13\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9\r\n**Cookie: G_ENABLED_IDPS=google; g_state={"i_l":0}; csid=kkJIz6LddA4y5zXFTF3nE7mVLzQffmV3**\r\nSec-WebSocket-Key: ASDasdASDasdASDasd==\r\nSec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\nSec-WebSocket-Protocol: wamp.2.json, wamp.2.msgpack\r\n\r\n'

[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] received HTTP status line in opening handshake : GET /ws HTTP/1.1
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] received HTTP headers in opening handshake : {'host': 'test.dev:8084', 'connection': 'Upgrade', 'pragma': 'no-cache', 'cache-control': 'no-cache', 'user-agent': '...Chrome/96.0.4664.93...', 'upgrade': 'websocket', 'origin': 'https://test.dev:8080', 'sec-websocket-version': '13', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'en-US,en;q=0.9', 'cookie': 'G_ENABLED_IDPS=google; g_state={"i_l":0}; csid=kkJIz6LddA4y5zXFTF3nE7mVLzQffmV3', 'sec-websocket-key': 'ASDasdASDasdASDasd==', 'sec-websocket-extensions': 'permessage-deflate; client_max_window_bits', 'sec-websocket-protocol': 'wamp.2.json, wamp.2.msgpack'}
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] skipping opening handshake port checking - neither WS URL nor external port set
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] Hybi protocol detected
[Router 2060793 crossbar.router.cookiestore.CookieStore] **Parsing cookie from** {... **'cookie': 'G_ENABLED_IDPS=google; g_state={"i_l":0}; csid=kkJIz6LddA4y5zXFTF3nE7mVLzQffmV3',** ...}
[Router 2060793 crossbar.router.cookiestore.CookieStore] **New cookie jmW4Bgy+V79ppSC87UKAH++yU8sGqYyQ created**
[Router 2060793 crossbar.router.cookiestore.CookieStore] **Cookie jmW4Bgy+V79ppSC87UKAH++yU8sGqYyQ stored**
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] Setting new cookie: csid=jmW4Bgy+V79ppSC87UKAH++yU8sGqYyQ;max-age=1209600;Secure;HttpOnly;SameSite=Strict
[Router 2060793 crossbar.router.cookiestore.CookieStore] Adding proto <crossbar.router.protocol.WampWebSocketServerProtocol object at 0x0000000004bf3168> to cookie jmW4Bgy+V79ppSC87UKAH++yU8sGqYyQ
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] Cookie tracking enabled on WebSocket connection <crossbar.router.protocol.WampWebSocketServerProtocol object at 0x0000000004bf3168>
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] Cookie-based authentication disabled
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] parsed WebSocket extension 'permessage-deflate' with params '{'client_max_window_bits': [True]}'
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] sending HTTP response:

HTTP/1.1 101 Switching Protocols
Server: Crossbar
Upgrade: WebSocket
Connection: Upgrade
Set-Cookie: csid=jmW4Bgy+V79ppSC87UKAH++yU8sGqYyQ;max-age=1209600;Secure;HttpOnly;SameSite=Strict
Sec-WebSocket-Protocol: wamp.2.json
Sec-WebSocket-Accept: ZXCzxcZCXzxcZCXzxc=
Sec-WebSocket-Extensions: permessage-deflate

[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] **openHandshakeTimeoutCall.cancel**
[Router 2060793 crossbar.router.session.RouterSession] **Client session connected** - transport: {'type': 'websocket', 'protocol': 'wamp.2.json', 'peer': 'tcp4:192.168.1.5:56973', 'http_headers_received': {**'cookie': 'G_ENABLED_IDPS=google; g_state={"i_l":0}; csid=kkJIz6LddA4y5zXFTF3nE7mVLzQffmV3'**, 'host': 'test.dev:8084', 'connection': 'Upgrade', 'pragma': 'no-cache', 'cache-control': 'no-cache', 'user-agent': '...Chrome/96.0.4664.93...', 'upgrade': 'websocket', 'origin': 'https://test.dev:8080', 'sec-websocket-version': '13', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'en-US,en;q=0.9', 'sec-websocket-key': 'ASDasdASDasdASDasd==', 'sec-websocket-extensions': 'permessage-deflate; client_max_window_bits', 'sec-websocket-protocol': 'wamp.2.json, wamp.2.msgpack'}, 'http_headers_sent': {'Set-Cookie': 'csid=jmW4Bgy+V79ppSC87UKAH++yU8sGqYyQ;max-age=1209600;Secure;HttpOnly;SameSite=Strict'}, 'websocket_extensions_in_use': [{'extension': 'permessage-deflate', 'is_server': True, 'server_no_context_takeover': False, 'client_no_context_takeover': False, 'server_max_window_bits': 15, 'client_max_window_bits': 15, 'mem_level': 8}], 'cbtid': 'jmW4Bgy+V79ppSC87UKAH++yU8sGqYyQ', 'channel_id': '...'}
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] RX compressed [length]: octets
[Router 2060793 crossbar.router.session.RouterSession] <crossbar.router.session.RouterSession.onHello> **processing authmethods=['ticket', 'cookie']**, authextra={....}
[Router 2060793 crossbar.router.auth.ticket.PendingAuthTicket] <crossbar.router.auth.pending.PendingAuth._init_function_authenticator> authenticator realm "system" set from session
[Router 2060793 crossbar.worker.router.RouterController] <crossbar.worker.router.RouterController.has_realm>(realm="system") -> True
[Router 2060793 crossbar.router.auth.ticket.PendingAuthTicket] <crossbar.router.auth.pending.PendingAuth._init_function_authenticator> authenticator role "trusted" set from session
[Router 2060793 crossbar.worker.router.RouterController] <crossbar.worker.router.RouterController.has_role>(realm="system", authrole="trusted") -> True
[Router 2060793 crossbar.router.auth.ticket.PendingAuthTicket] initializing authenticator service session for realm "system" with authrole "trusted" .. <crossbar.router.auth.pending.PendingAuth._init_dynamic_authenticator>
[Router 2060793 crossbar.worker.router.RouterController] <crossbar.worker.router.RouterController.get_service_session>(realm="system", authrole="trusted") -> <crossbar.router.service.RouterServiceAgent object at 0x000000000452d088>
[Router 2060793 crossbar.router.auth.ticket.PendingAuthTicket] authenticator service session 3247402291370148 attached to realm "system" with authrole "trusted" <crossbar.router.auth.pending.PendingAuth._init_dynamic_authenticator>
[Router 2060793 crossbar.router.session.RouterSession] <crossbar.router.session.RouterSession.onMessage>::_on_success(res=Challenge(method=ticket, extra={}))
[Router 2060793 crossbar.router.protocol.WampWebSocketServerProtocol] RX compressed [length]: octets
[Router 2060793 crossbar.router.session.RouterSession] onAuthenticate: ... {}
[Router 2060793 crossbar.router.role.RouterRole] CrossbarRouterTrustedRole.authorize trusted auth.create_ticket_session call {}
[Router 2060793 crossbar.router.router.Router] Authorized action 'call' for URI 'auth.create_ticket_session' by session 3247402291370148 with authid 'routerworker-worker001-realm-realm001-serviceagent' and authrole 'trusted' -> authorization: {'allow': True, 'cache': False, 'disclose': True}
[Router 2060793 crossbar.router.dealer.Dealer] <crossbar.router.dealer.Dealer.processCall>::on_authorize_success() - permission GRANTED for CALL of procedure "auth.create_ticket_session" [realm="system", session_id=3247402291370148, authid="routerworker-worker001-realm-realm001-serviceagent", authrole="trusted"]
[Router 2060793 crossbar.router.router.Router] **Validate 'call' for 'auth.create_ticket_session'**
...
yankos commented 2 years ago

Very simple code for reproduce an issue. The order of the cookies in the header matters.

Tested on Python 3.8, Python 3.9, PyPy 3.7.1, PyPy 3.7.5

Python 3.8.8 (tags/v3.8.8:024d805, Feb 19 2021, 13:18:16) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from http.cookies import SimpleCookie

>>> cookie_raw_only_first = 'G_ENABLED_IDPS=google; g_state={"i_l":0}; csid=kkJIz6LddA4y5zXFTF3nE7mVLzQffmV3'
>>> print(SimpleCookie(cookie_raw_only_first).keys())
dict_keys(['G_ENABLED_IDPS'])

>>> cookie_raw_all = 'G_ENABLED_IDPS=google; csid=kkJIz6LddA4y5zXFTF3nE7mVLzQffmV3'
>>> print(SimpleCookie(cookie_raw_all).keys())
dict_keys(['G_ENABLED_IDPS', 'csid'])

>>> cookie_raw_csid_ok_but_not_full = 'G_ENABLED_IDPS=google; csid=kkJIz6LddA4y5zXFTF3nE7mVLzQffmV3; g_state={"i_l":0}'
>>> print(SimpleCookie(cookie_raw_csid_ok_but_not_full).keys())
dict_keys(['G_ENABLED_IDPS', 'csid'])

>>> cookie_raw_csid_strict_json = 'G_ENABLED_IDPS=google; g_state="{\"i_l\":0}"; csid=kkJIz6LddA4y5zXFTF3nE7mVLzQffmV3'
>>> print(SimpleCookie(cookie_raw_csid_strict_json).keys())
dict_keys(['G_ENABLED_IDPS'])
>>>
yankos commented 2 years ago

@oberstet Can I help you with this PR?

oberstet commented 2 years ago

@yankos sorry, it's not a priority for me, and I lack time ...