From 5dee0873d19f303c8763d6c335dc23ee5ebf9418 Mon Sep 17 00:00:00 2001 From: GulliblePsychologist Date: Sat, 11 Jan 2020 16:20:19 +0000 Subject: [PATCH 1/2] Allow X-Forwarded-For to be accepted for the WebSocket connections. --- evennia/server/portal/portal.py | 2 ++ evennia/server/portal/webclient.py | 9 +++++++-- evennia/settings_default.py | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/evennia/server/portal/portal.py b/evennia/server/portal/portal.py index f86b648ef2..8a325aa151 100644 --- a/evennia/server/portal/portal.py +++ b/evennia/server/portal/portal.py @@ -58,6 +58,7 @@ SSL_PORTS = settings.SSL_PORTS SSH_PORTS = settings.SSH_PORTS WEBSERVER_PORTS = settings.WEBSERVER_PORTS WEBSOCKET_CLIENT_PORT = settings.WEBSOCKET_CLIENT_PORT +WEBSOCKET_TRUST_X_FORWARDED_FOR = settings.WEBSOCKET_TRUST_X_FORWARDED_FOR TELNET_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.TELNET_INTERFACES SSL_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.SSL_INTERFACES @@ -386,6 +387,7 @@ if WEBSERVER_ENABLED: factory.noisy = False factory.protocol = webclient.WebSocketClient factory.sessionhandler = PORTAL_SESSIONS + factory.setProtocolOptions(trustXForwardedFor=WEBSOCKET_TRUST_X_FORWARDED_FOR) websocket_service = internet.TCPServer( port, factory, interface=w_interface ) diff --git a/evennia/server/portal/webclient.py b/evennia/server/portal/webclient.py index b501a3df2e..118a8bd722 100644 --- a/evennia/server/portal/webclient.py +++ b/evennia/server/portal/webclient.py @@ -73,8 +73,13 @@ class WebSocketClient(WebSocketServerProtocol, Session): This is called when the WebSocket connection is fully established. """ - client_address = self.transport.client - client_address = client_address[0] if client_address else None + if 'x-forwarded-for' in self.http_headers and self.trustXForwardedFor: + addresses = [x.strip() for x in self.http_headers['x-forwarded-for'].split(',')] + trusted_addresses = addresses[-self.trustXForwardedFor:] + client_address = trusted_addresses[0] + else: + client_address = self.transport.client + client_address = client_address[0] if client_address else None self.init_session("websocket", client_address, self.factory.sessionhandler) csession = self.get_client_session() # this sets self.csessid diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 6c4add4d6a..41559b3871 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -102,6 +102,9 @@ WEBSOCKET_CLIENT_INTERFACE = "0.0.0.0" # the client will itself figure out this url based on the server's hostname. # e.g. ws://external.example.com or wss://external.example.com:443 WEBSOCKET_CLIENT_URL = None +# Number of trusted web servers (reverse proxies) in front of this server which +# set the X-Forwarded-For header. +WEBSOCKET_TRUST_X_FORWARDED_FOR = None # This determine's whether Evennia's custom admin page is used, or if the # standard Django admin is used. EVENNIA_ADMIN = True From bfe7a2e6e6d45e9c7af3cc57fee8ce3ea3560be8 Mon Sep 17 00:00:00 2001 From: GulliblePsychologist Date: Tue, 14 Jan 2020 21:51:19 +0000 Subject: [PATCH 2/2] Remove WEBSOCKET_TRUST_X_FORWARDED_FOR, use UPSTREAM_IPS --- evennia/server/portal/portal.py | 2 -- evennia/server/portal/webclient.py | 18 ++++++++++++------ evennia/settings_default.py | 3 --- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/evennia/server/portal/portal.py b/evennia/server/portal/portal.py index 8a325aa151..f86b648ef2 100644 --- a/evennia/server/portal/portal.py +++ b/evennia/server/portal/portal.py @@ -58,7 +58,6 @@ SSL_PORTS = settings.SSL_PORTS SSH_PORTS = settings.SSH_PORTS WEBSERVER_PORTS = settings.WEBSERVER_PORTS WEBSOCKET_CLIENT_PORT = settings.WEBSOCKET_CLIENT_PORT -WEBSOCKET_TRUST_X_FORWARDED_FOR = settings.WEBSOCKET_TRUST_X_FORWARDED_FOR TELNET_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.TELNET_INTERFACES SSL_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.SSL_INTERFACES @@ -387,7 +386,6 @@ if WEBSERVER_ENABLED: factory.noisy = False factory.protocol = webclient.WebSocketClient factory.sessionhandler = PORTAL_SESSIONS - factory.setProtocolOptions(trustXForwardedFor=WEBSOCKET_TRUST_X_FORWARDED_FOR) websocket_service = internet.TCPServer( port, factory, interface=w_interface ) diff --git a/evennia/server/portal/webclient.py b/evennia/server/portal/webclient.py index 118a8bd722..45c5b88c81 100644 --- a/evennia/server/portal/webclient.py +++ b/evennia/server/portal/webclient.py @@ -29,6 +29,7 @@ _RE_SCREENREADER_REGEX = re.compile( r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE ) _CLIENT_SESSIONS = mod_import(settings.SESSION_ENGINE).SessionStore +_UPSTREAM_IPS = settings.UPSTREAM_IPS CLOSE_NORMAL = WebSocketServerProtocol.CLOSE_STATUS_CODE_NORMAL @@ -73,13 +74,18 @@ class WebSocketClient(WebSocketServerProtocol, Session): This is called when the WebSocket connection is fully established. """ - if 'x-forwarded-for' in self.http_headers and self.trustXForwardedFor: + client_address = self.transport.client + client_address = client_address[0] if client_address else None + + if client_address in _UPSTREAM_IPS and 'x-forwarded-for' in self.http_headers: addresses = [x.strip() for x in self.http_headers['x-forwarded-for'].split(',')] - trusted_addresses = addresses[-self.trustXForwardedFor:] - client_address = trusted_addresses[0] - else: - client_address = self.transport.client - client_address = client_address[0] if client_address else None + addresses.reverse() + + for addr in addresses: + if addr not in _UPSTREAM_IPS: + client_address = addr + break + self.init_session("websocket", client_address, self.factory.sessionhandler) csession = self.get_client_session() # this sets self.csessid diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 41559b3871..6c4add4d6a 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -102,9 +102,6 @@ WEBSOCKET_CLIENT_INTERFACE = "0.0.0.0" # the client will itself figure out this url based on the server's hostname. # e.g. ws://external.example.com or wss://external.example.com:443 WEBSOCKET_CLIENT_URL = None -# Number of trusted web servers (reverse proxies) in front of this server which -# set the X-Forwarded-For header. -WEBSOCKET_TRUST_X_FORWARDED_FOR = None # This determine's whether Evennia's custom admin page is used, or if the # standard Django admin is used. EVENNIA_ADMIN = True