new: secured the web ui with CORS

This commit is contained in:
Simone Margaritelli 2019-10-20 16:09:27 +02:00
parent 539df810ed
commit d45e8c7ba0
2 changed files with 47 additions and 3 deletions

View File

@ -175,6 +175,7 @@ ui:
video: video:
enabled: true enabled: true
address: '0.0.0.0' address: '0.0.0.0'
origin: '*'
port: 8080 port: 8080

View File

@ -73,13 +73,30 @@ SHUTDOWN = """<html>
class Handler(BaseHTTPRequestHandler): class Handler(BaseHTTPRequestHandler):
AllowedOrigin = '*'
# suppress internal logging # suppress internal logging
def log_message(self, format, *args): def log_message(self, format, *args):
return return
def _send_cors_headers(self):
# misc security
self.send_header("X-Frame-Options", "DENY")
self.send_header("X-Content-Type-Options", "nosniff")
self.send_header("X-XSS-Protection", "1; mode=block")
self.send_header("Referrer-Policy", "same-origin")
# cors
self.send_header("Access-Control-Allow-Origin", Handler.AllowedOrigin)
self.send_header('Access-Control-Allow-Credentials', 'true')
self.send_header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
self.send_header("Access-Control-Allow-Headers",
"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
self.send_header("Vary", "Origin")
# just render some html in a 200 response # just render some html in a 200 response
def _html(self, html): def _html(self, html):
self.send_response(200) self.send_response(200)
self._send_cors_headers()
self.send_header('Content-type', 'text/html') self.send_header('Content-type', 'text/html')
self.end_headers() self.end_headers()
try: try:
@ -98,10 +115,11 @@ class Handler(BaseHTTPRequestHandler):
# serve the PNG file with the display image # serve the PNG file with the display image
def _image(self): def _image(self):
global frame_path, frame_ctype global frame_lock, frame_path, frame_ctype
with frame_lock: with frame_lock:
self.send_response(200) self.send_response(200)
self._send_cors_headers()
self.send_header('Content-type', frame_ctype) self.send_header('Content-type', frame_ctype)
self.end_headers() self.end_headers()
try: try:
@ -110,13 +128,32 @@ class Handler(BaseHTTPRequestHandler):
except: except:
pass pass
def do_OPTIONS(self):
self.send_response(200)
self._send_cors_headers()
self.end_headers()
# check the Origin header vs CORS
def _is_allowed(self):
origin = self.headers.get('origin')
if origin == "":
logging.warning("request with no Origin header from %s" % self.address_string())
return False
if Handler.AllowedOrigin != '*':
if origin != Handler.AllowedOrigin and not origin.starts_with(Handler.AllowedOrigin):
logging.warning("request with blocked Origin from %s: %s" % (self.address_string(), origin))
return False
return True
# main entry point of the http server # main entry point of the http server
def do_GET(self): def do_GET(self):
global frame_lock if not self._is_allowed():
return
if self.path == '/': if self.path == '/':
self._index() self._index()
elif self.path.startswith('/shutdown'): elif self.path.startswith('/shutdown'):
self._shutdown() self._shutdown()
@ -133,6 +170,12 @@ class Server(object):
self._address = config['video']['address'] self._address = config['video']['address']
self._httpd = None self._httpd = None
if 'origin' in config['video'] and config['video']['origin'] != '*':
Handler.AllowedOrigin = config['video']['origin']
else:
logging.warning("THE WEB UI IS RUNNING WITH ALLOWED ORIGIN SET TO *, READ WHY YOU SHOULD CHANGE IT HERE \
https://developer.mozilla.org/it/docs/Web/HTTP/CORS")
if self._enabled: if self._enabled:
_thread.start_new_thread(self._http_serve, ()) _thread.start_new_thread(self._http_serve, ())