diff --git a/src/Config.py b/src/Config.py index 8a847bf3..ba519a6b 100644 --- a/src/Config.py +++ b/src/Config.py @@ -241,6 +241,7 @@ class Config: self.parser.add_argument('--log-rotate-backup-count', help='Log rotate backup count', default=5, type=int) self.parser.add_argument('--language', help='Web interface language', default=language, metavar='language') + self.parser.add_argument('--ui-ip-protect', help="Protect UI server from being accessed through third-party pages and on unauthorized cross-origin pages (enabled by default when serving on localhost IPs; doesn't work with non-local IPs, need testing with host names)", choices=['always', 'local', 'off'], default='local') self.parser.add_argument('--ui-ip', help='Web interface bind address', default="127.0.0.1", metavar='ip') self.parser.add_argument('--ui-port', help='Web interface bind port', default=43110, type=int, metavar='port') self.parser.add_argument('--ui-site-port', help='Port for serving site content, defaults to ui_port+1', default=None, metavar='port') @@ -459,6 +460,14 @@ class Config: self.arguments = self.parser.parse_args(argv[1:]) if self.arguments.ui_site_port is None: self.arguments.ui_site_port = self.arguments.ui_port + 1 + if self.arguments.ui_ip_protect == 'always': + self.arguments.ui_check_cors = True + elif self.arguments.ui_ip_protect == 'off': + self.arguments.ui_check_cors = False + elif self.arguments.ui_ip_protect == 'local': + self.arguments.ui_check_cors = self.arguments.ui_ip == '127.0.0.1' or self.arguments.ui_ip == '::1' + else: + raise Exception("Wrong argparse result") def parseConfig(self, argv): argv = self.fixArgs(argv) diff --git a/src/Ui/UiRequest.py b/src/Ui/UiRequest.py index 34af96e2..70470dba 100644 --- a/src/Ui/UiRequest.py +++ b/src/Ui/UiRequest.py @@ -82,7 +82,7 @@ class UiRequest: self.learnHost(host) return True - if ":" in host and helper.isIp(host.rsplit(":", 1)[0]): # Test without port + if ":" in host and helper.isIp(host.rsplit(":", 1)[0].lstrip("[").rstrip("]")): # Test without port self.learnHost(host) return True @@ -165,14 +165,14 @@ class UiRequest: is_navigate = self.env.get('HTTP_SEC_FETCH_MODE') == 'navigate' is_iframe = self.env.get('HTTP_SEC_FETCH_DEST') == 'iframe' - if is_navigate and not is_iframe and self.is_data_request: + if ((is_navigate and not is_iframe) or not config.ui_check_cors) and self.is_data_request: host = self.getHostWithoutPort() path_info = self.env['PATH_INFO'] query_string = self.env['QUERY_STRING'] protocol = self.env['wsgi.url_scheme'] return self.actionRedirect(f'{protocol}://{host}:{config.ui_port}{path_info}?{query_string}') - if self.isCrossOriginRequest(): + if config.ui_check_cors and self.isCrossOriginRequest(): # we are still exposed by answering on port self.log.warning('Cross-origin request detected. Someone might be trying to analyze your 0net usage') return [] @@ -382,10 +382,12 @@ class UiRequest: port = int(self.env['SERVER_PORT']) if port == config.ui_port: other_port = config.ui_site_port + frame_src = '*' else: other_port = config.ui_port - site_server = f'{host}:{other_port}' - headers["Content-Security-Policy"] = f"default-src 'none'; script-src 'nonce-{script_nonce}'; img-src 'self' blob: data:; style-src 'self' blob: 'unsafe-inline'; connect-src *; frame-src {site_server}" + frame_src = 'self' + + headers["Content-Security-Policy"] = f"default-src 'none'; script-src 'nonce-{script_nonce}'; img-src 'self' blob: data:; style-src 'self' blob: 'unsafe-inline'; connect-src *; frame-src {frame_src}" if allow_ajax: headers["Access-Control-Allow-Origin"] = "null" diff --git a/src/util/helper.py b/src/util/helper.py index af65f727..8c7c6fff 100644 --- a/src/util/helper.py +++ b/src/util/helper.py @@ -325,7 +325,10 @@ def openBrowser(agent): if agent and agent != "False": print(f"Opening browser: {agent}...") ui_ip = config.ui_ip if config.ui_ip != "*" else "127.0.0.1" - url = f'http://{ui_ip}:{config.ui_port}/{config.homepage}' + if ':' in ui_ip: # IPv6 + url = f'http://[{ui_ip}]:{config.ui_port}/{config.homepage}' + else: # IPv4 + url = f'http://{ui_ip}:{config.ui_port}/{config.homepage}' try: import subprocess return subprocess.Popen([config.open_browser, url])