Disallow unknown script by using csp header for wrapper
This commit is contained in:
parent
481e029600
commit
99f01475a0
1 changed files with 16 additions and 6 deletions
|
@ -46,6 +46,7 @@ class UiRequest(object):
|
||||||
|
|
||||||
self.start_response = start_response # Start response function
|
self.start_response = start_response # Start response function
|
||||||
self.user = None
|
self.user = None
|
||||||
|
self.script_nonce = None # Nonce for script tags in wrapper html
|
||||||
|
|
||||||
def isHostAllowed(self, host):
|
def isHostAllowed(self, host):
|
||||||
if host in self.server.allowed_hosts:
|
if host in self.server.allowed_hosts:
|
||||||
|
@ -222,7 +223,7 @@ class UiRequest(object):
|
||||||
return referer
|
return referer
|
||||||
|
|
||||||
# Send response headers
|
# Send response headers
|
||||||
def sendHeader(self, status=200, content_type="text/html", noscript=False, allow_ajax=False, extra_headers=[]):
|
def sendHeader(self, status=200, content_type="text/html", noscript=False, allow_ajax=False, script_nonce=None, extra_headers=[]):
|
||||||
headers = {}
|
headers = {}
|
||||||
headers["Version"] = "HTTP/1.1"
|
headers["Version"] = "HTTP/1.1"
|
||||||
headers["Connection"] = "Keep-Alive"
|
headers["Connection"] = "Keep-Alive"
|
||||||
|
@ -233,6 +234,8 @@ class UiRequest(object):
|
||||||
|
|
||||||
if noscript:
|
if noscript:
|
||||||
headers["Content-Security-Policy"] = "default-src 'none'; sandbox allow-top-navigation allow-forms; img-src 'self'; font-src 'self'; media-src 'self'; style-src 'self' 'unsafe-inline';"
|
headers["Content-Security-Policy"] = "default-src 'none'; sandbox allow-top-navigation allow-forms; img-src 'self'; font-src 'self'; media-src 'self'; style-src 'self' 'unsafe-inline';"
|
||||||
|
elif script_nonce:
|
||||||
|
headers["Content-Security-Policy"] = "script-src 'nonce-%s'" % script_nonce
|
||||||
|
|
||||||
if allow_ajax:
|
if allow_ajax:
|
||||||
headers["Access-Control-Allow-Origin"] = "null"
|
headers["Access-Control-Allow-Origin"] = "null"
|
||||||
|
@ -285,6 +288,7 @@ class UiRequest(object):
|
||||||
def actionWrapper(self, path, extra_headers=None):
|
def actionWrapper(self, path, extra_headers=None):
|
||||||
if not extra_headers:
|
if not extra_headers:
|
||||||
extra_headers = {}
|
extra_headers = {}
|
||||||
|
script_nonce = self.getScriptNonce()
|
||||||
|
|
||||||
match = re.match("/(?P<address>[A-Za-z0-9\._-]+)(?P<inner_path>/.*|$)", path)
|
match = re.match("/(?P<address>[A-Za-z0-9\._-]+)(?P<inner_path>/.*|$)", path)
|
||||||
just_added = False
|
just_added = False
|
||||||
|
@ -334,14 +338,14 @@ class UiRequest(object):
|
||||||
if not site:
|
if not site:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.sendHeader(extra_headers=extra_headers)
|
self.sendHeader(extra_headers=extra_headers, script_nonce=script_nonce)
|
||||||
|
|
||||||
min_last_announce = (time.time() - site.announcer.time_last_announce) / 60
|
min_last_announce = (time.time() - site.announcer.time_last_announce) / 60
|
||||||
if min_last_announce > 60 and site.settings["serving"] and not just_added:
|
if min_last_announce > 60 and site.settings["serving"] and not just_added:
|
||||||
site.log.debug("Site requested, but not announced recently (last %.0fmin ago). Updating..." % min_last_announce)
|
site.log.debug("Site requested, but not announced recently (last %.0fmin ago). Updating..." % min_last_announce)
|
||||||
gevent.spawn(site.update, announce=True)
|
gevent.spawn(site.update, announce=True)
|
||||||
|
|
||||||
return iter([self.renderWrapper(site, path, inner_path, title, extra_headers)])
|
return iter([self.renderWrapper(site, path, inner_path, title, extra_headers, script_nonce=script_nonce)])
|
||||||
# Make response be sent at once (see https://github.com/HelloZeroNet/ZeroNet/issues/1092)
|
# Make response be sent at once (see https://github.com/HelloZeroNet/ZeroNet/issues/1092)
|
||||||
|
|
||||||
else: # Bad url
|
else: # Bad url
|
||||||
|
@ -368,7 +372,7 @@ class UiRequest(object):
|
||||||
|
|
||||||
return query_string
|
return query_string
|
||||||
|
|
||||||
def renderWrapper(self, site, path, inner_path, title, extra_headers, show_loadingscreen=None):
|
def renderWrapper(self, site, path, inner_path, title, extra_headers, show_loadingscreen=None, script_nonce=None):
|
||||||
file_inner_path = inner_path
|
file_inner_path = inner_path
|
||||||
if not file_inner_path:
|
if not file_inner_path:
|
||||||
file_inner_path = "index.html" # If inner path defaults to index.html
|
file_inner_path = "index.html" # If inner path defaults to index.html
|
||||||
|
@ -463,7 +467,8 @@ class UiRequest(object):
|
||||||
rev=config.rev,
|
rev=config.rev,
|
||||||
lang=config.language,
|
lang=config.language,
|
||||||
homepage=homepage,
|
homepage=homepage,
|
||||||
themeclass=themeclass
|
themeclass=themeclass,
|
||||||
|
script_nonce=script_nonce
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create a new wrapper nonce that allows to get one html file without the wrapper
|
# Create a new wrapper nonce that allows to get one html file without the wrapper
|
||||||
|
@ -472,6 +477,12 @@ class UiRequest(object):
|
||||||
self.server.wrapper_nonces.append(wrapper_nonce)
|
self.server.wrapper_nonces.append(wrapper_nonce)
|
||||||
return wrapper_nonce
|
return wrapper_nonce
|
||||||
|
|
||||||
|
def getScriptNonce(self):
|
||||||
|
if not self.script_nonce:
|
||||||
|
self.script_nonce = CryptHash.random(encoding="base64")
|
||||||
|
|
||||||
|
return self.script_nonce
|
||||||
|
|
||||||
# Create a new wrapper nonce that allows to get one site
|
# Create a new wrapper nonce that allows to get one site
|
||||||
def getAddNonce(self):
|
def getAddNonce(self):
|
||||||
add_nonce = CryptHash.random()
|
add_nonce = CryptHash.random()
|
||||||
|
@ -800,4 +811,3 @@ class UiRequest(object):
|
||||||
<h1>%s</h1>
|
<h1>%s</h1>
|
||||||
<h2>%s</h3>
|
<h2>%s</h3>
|
||||||
""" % (title, cgi.escape(message))
|
""" % (title, cgi.escape(message))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue