Add 2 arguments to websockify.WSRequestHandler
This patch adds 2 arguments to websockify.WSRequestHandler for security: * file_only: returns 404 response if non-file contents are requested. Required to disable directory listing. * no_parent: returns 403 response if contents out of the web root are requested. Required to disable directory traversal.
This commit is contained in:
parent
b7f255ce0b
commit
888e75a8fb
|
@ -92,7 +92,7 @@ Sec-WebSocket-Accept: %s\r
|
||||||
|
|
||||||
def __init__(self, listen_host='', listen_port=None, source_is_ipv6=False,
|
def __init__(self, listen_host='', listen_port=None, source_is_ipv6=False,
|
||||||
verbose=False, cert='', key='', ssl_only=None,
|
verbose=False, cert='', key='', ssl_only=None,
|
||||||
daemon=False, record='', web='',
|
daemon=False, record='', web='', file_only=False, no_parent=False,
|
||||||
run_once=False, timeout=0, idle_timeout=0):
|
run_once=False, timeout=0, idle_timeout=0):
|
||||||
|
|
||||||
# settings
|
# settings
|
||||||
|
@ -110,6 +110,9 @@ Sec-WebSocket-Accept: %s\r
|
||||||
self.ws_connection = False
|
self.ws_connection = False
|
||||||
self.handler_id = 1
|
self.handler_id = 1
|
||||||
|
|
||||||
|
self.file_only = file_only
|
||||||
|
self.no_parent = no_parent
|
||||||
|
|
||||||
# Make paths settings absolute
|
# Make paths settings absolute
|
||||||
self.cert = os.path.abspath(cert)
|
self.cert = os.path.abspath(cert)
|
||||||
self.key = self.web = self.record = ''
|
self.key = self.web = self.record = ''
|
||||||
|
@ -620,7 +623,8 @@ Sec-WebSocket-Accept: %s\r
|
||||||
self.scheme = "ws"
|
self.scheme = "ws"
|
||||||
stype = "Plain non-SSL (ws://)"
|
stype = "Plain non-SSL (ws://)"
|
||||||
|
|
||||||
wsh = WSRequestHandler(retsock, address, not self.web)
|
wsh = WSRequestHandler(retsock, address, not self.web,
|
||||||
|
self.file_only, self.no_parent)
|
||||||
if wsh.last_code == 101:
|
if wsh.last_code == 101:
|
||||||
# Continue on to handle WebSocket upgrade
|
# Continue on to handle WebSocket upgrade
|
||||||
pass
|
pass
|
||||||
|
@ -859,11 +863,16 @@ Sec-WebSocket-Accept: %s\r
|
||||||
|
|
||||||
# HTTP handler with WebSocket upgrade support
|
# HTTP handler with WebSocket upgrade support
|
||||||
class WSRequestHandler(SimpleHTTPRequestHandler):
|
class WSRequestHandler(SimpleHTTPRequestHandler):
|
||||||
def __init__(self, req, addr, only_upgrade=False):
|
def __init__(self, req, addr, only_upgrade=False, file_only=False,
|
||||||
|
no_parent=False):
|
||||||
self.only_upgrade = only_upgrade # only allow upgrades
|
self.only_upgrade = only_upgrade # only allow upgrades
|
||||||
|
self.webroot = os.path.realpath(".")
|
||||||
|
self.file_only = file_only
|
||||||
|
self.no_parent = no_parent
|
||||||
SimpleHTTPRequestHandler.__init__(self, req, addr, object())
|
SimpleHTTPRequestHandler.__init__(self, req, addr, object())
|
||||||
|
|
||||||
def do_GET(self):
|
def do_GET(self):
|
||||||
|
abspath = os.path.realpath("." + (self.path.split('?')[0]))
|
||||||
if (self.headers.get('upgrade') and
|
if (self.headers.get('upgrade') and
|
||||||
self.headers.get('upgrade').lower() == 'websocket'):
|
self.headers.get('upgrade').lower() == 'websocket'):
|
||||||
|
|
||||||
|
@ -874,6 +883,10 @@ class WSRequestHandler(SimpleHTTPRequestHandler):
|
||||||
# Normal web request responses are disabled
|
# Normal web request responses are disabled
|
||||||
self.last_code = 405
|
self.last_code = 405
|
||||||
self.last_message = "405 Method Not Allowed"
|
self.last_message = "405 Method Not Allowed"
|
||||||
|
elif self.file_only and not os.path.isfile(abspath):
|
||||||
|
self.send_response(404, "No such file")
|
||||||
|
elif self.no_parent and not abspath.startswith(self.webroot):
|
||||||
|
self.send_response(403, "Hidden resources")
|
||||||
else:
|
else:
|
||||||
SimpleHTTPRequestHandler.do_GET(self)
|
SimpleHTTPRequestHandler.do_GET(self)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue