diff options
author | 2014-08-04 13:34:26 +0800 | |
---|---|---|
committer | 2014-08-04 13:34:26 +0800 | |
commit | 4ae2753025311e9bcc9818dcc26b9e89f229b291 (patch) | |
tree | 85ee782510bd67065eba7ef79801361f8d72021c /share/tools/web_config/webconfig.py | |
parent | 8844f0c142ade7d6dfea20fc65432b4f97fb92c9 (diff) |
Authenticate connections to web_config service
- Require all requests to use a session path.
- Use a redirect file to avoid exposing the '/start' URL on the
command line, as it contains the cookie value.
Fix for CVE-2014-2914.
Closes #1438.
Diffstat (limited to 'share/tools/web_config/webconfig.py')
-rwxr-xr-x | share/tools/web_config/webconfig.py | 69 |
1 files changed, 64 insertions, 5 deletions
diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py index c3daef5f..55ab372e 100755 --- a/share/tools/web_config/webconfig.py +++ b/share/tools/web_config/webconfig.py @@ -26,7 +26,7 @@ if term: os.environ['TERM'] = term import subprocess -import re, socket, cgi, select, time, glob +import re, socket, cgi, select, time, glob, random, string try: import json except ImportError: @@ -693,9 +693,16 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): else: font_size = '18pt' return font_size - def do_GET(self): p = self.path + + authpath = '/' + authkey + if p.startswith(authpath): + p = p[len(authpath):] + else: + return self.send_error(403) + self.path = p + if p == '/colors/': output = self.do_get_colors() elif p == '/functions/': @@ -727,6 +734,14 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): def do_POST(self): p = self.path + + authpath = '/' + authkey + if p.startswith(authpath): + p = p[len(authpath):] + else: + return self.send_error(403) + self.path = p + if IS_PY2: ctype, pdict = cgi.parse_header(self.headers.getheader('content-type')) else: # Python 3 @@ -788,6 +803,18 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): """ Disable request logging """ pass +redirect_template_html = """ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="refresh" content="0;URL='%s'" /> + </head> + <body> + <p><a href="%s">Start the Fish Web config</a></p> + </body> +</html> +""" + # find fish fish_bin_dir = os.environ.get('__fish_bin_dir') fish_bin_path = None @@ -823,6 +850,9 @@ initial_wd = os.getcwd() where = os.path.dirname(sys.argv[0]) os.chdir(where) +# Generate a 16-byte random key as a hexadecimal string +authkey = hex(random.getrandbits(16*4))[2:] + # Try to find a suitable port PORT = 8000 while PORT <= 9000: @@ -852,9 +882,36 @@ if len(sys.argv) > 1: initial_tab = '#' + tab break -url = 'http://localhost:%d/%s' % (PORT, initial_tab) -print("Web config started at '%s'. Hit enter to stop." % url) -webbrowser.open(url) +url = 'http://localhost:%d/%s/%s' % (PORT, authkey, initial_tab) + +# Create temporary file to hold redirect to real server +# This prevents exposing the URL containing the authentication key on the command line +# (see CVE-2014-2914 or https://github.com/fish-shell/fish-shell/issues/1438) +if 'XDG_CACHE_HOME' in os.environ: + dirname = os.path.expanduser(os.path.expandvars('$XDG_CACHE_HOME/fish/')) +else: + dirname = os.path.expanduser('~/.cache/fish/') + +os.umask(0o0077) +try: + os.makedirs(dirname, 0o0700) +except OSError as e: + if e.errno == 17: + pass + else: + raise e + +randtoken = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) +filename = dirname + 'web_config-%s.html' % randtoken + +f = open(filename, 'w') +f.write(redirect_template_html % (url, url)) +f.close() + +# Open temporary file as URL +fileurl = 'file://' + filename +print("Web config started at '%s'. Hit enter to stop." % fileurl) +webbrowser.open(fileurl) # Select on stdin and httpd stdin_no = sys.stdin.fileno() @@ -871,3 +928,5 @@ try: except KeyboardInterrupt: print("\nShutting down.") +# Clean up temporary file +os.remove(filename) |