Update script tags with nonce attribute

This commit is contained in:
Théophile Diot 2024-02-21 11:51:58 +01:00
parent c8bc2b5eeb
commit 70208d1d01
No known key found for this signature in database
GPG key ID: 248FEA4BAE400D06
7 changed files with 70 additions and 49 deletions

View file

@ -199,6 +199,7 @@ try:
TO_FLASH=[],
DARK_MODE=False,
CURRENT_TOTP_TOKEN=None,
SCRIPT_NONCE=sha256(urandom(32)).hexdigest(),
)
except FileNotFoundError as e:
app.logger.error(repr(e), e.filename)
@ -288,10 +289,32 @@ def manage_bunkerweb(method: str, *args, operation: str = "reloads", is_draft: b
app.config["RELOADING"] = False
@app.before_request
def generate_nonce():
app.config["SCRIPT_NONCE"] = sha256(urandom(32)).hexdigest()
@app.context_processor
def inject_variables():
return dict(
dark_mode=app.config["DARK_MODE"],
script_nonce=app.config["SCRIPT_NONCE"],
is_pro_version=PRO_VERSION,
plugins_pro=PRO_PLUGINS_LIST,
)
@app.after_request
def set_csp_header(response):
"""Set the Content-Security-Policy header to prevent XSS attacks."""
response.headers["Content-Security-Policy"] = "object-src 'none'; frame-ancestors 'self'; default-src 'self'"
response.headers["Content-Security-Policy"] = (
"object-src 'none';"
+ " frame-ancestors 'self';"
+ " default-src 'self' https://www.bunkerweb.io https://assets.bunkerity.com;"
+ f" script-src 'self' 'nonce-{app.config['SCRIPT_NONCE']}';"
+ " style-src 'self' 'unsafe-inline';"
+ " img-src 'self' data: https://assets.bunkerity.com;"
)
return response
@ -483,7 +506,7 @@ def totp():
if not current_user.is_two_factor_enabled or session.get("totp_validated", False):
return redirect(url_for("home"))
return render_template("totp.html", dark_mode=app.config["DARK_MODE"])
return render_template("totp.html")
@app.route("/home")
@ -542,9 +565,6 @@ def home():
services_ui_count=services_ui_count,
services_autoconf_count=services_autoconf_count,
username=current_user.get_id(),
dark_mode=app.config["DARK_MODE"],
is_pro_version=PRO_VERSION,
plugins_pro=PRO_PLUGINS_LIST,
)
@ -642,7 +662,11 @@ def account():
app.config["CURRENT_TOTP_TOKEN"] = secret_token
return render_template(
"account.html", username=current_user.get_id(), is_totp=current_user.is_two_factor_enabled, secret_token=secret_token, totp_qr_image=totp_qr_image, dark_mode=app.config["DARK_MODE"], is_pro_version=PRO_VERSION, plugins_pro=PRO_PLUGINS_LIST
"account.html",
username=current_user.get_id(),
is_totp=current_user.is_two_factor_enabled,
secret_token=secret_token,
totp_qr_image=totp_qr_image,
)
@ -685,7 +709,7 @@ def instances():
# Display instances
instances = app.config["INSTANCES"].get_instances()
return render_template("instances.html", title="Instances", instances=instances, username=current_user.get_id(), dark_mode=app.config["DARK_MODE"], is_pro_version=PRO_VERSION, plugins_pro=PRO_PLUGINS_LIST)
return render_template("instances.html", title="Instances", instances=instances, username=current_user.get_id())
@app.route("/services", methods=["GET", "POST"])
@ -807,9 +831,6 @@ def services():
for service in services
],
username=current_user.get_id(),
dark_mode=app.config["DARK_MODE"],
is_pro_version=PRO_VERSION,
plugins_pro=PRO_PLUGINS_LIST,
)
@ -866,7 +887,7 @@ def global_config():
)
# Display global config
return render_template("global_config.html", username=current_user.get_id(), dark_mode=app.config["DARK_MODE"], is_pro_version=PRO_VERSION, plugins_pro=PRO_PLUGINS_LIST)
return render_template("global_config.html", username=current_user.get_id())
@app.route("/configs", methods=["GET", "POST"])
@ -960,9 +981,6 @@ def configs():
)
],
username=current_user.get_id(),
dark_mode=app.config["DARK_MODE"],
is_pro_version=PRO_VERSION,
plugins_pro=PRO_PLUGINS_LIST,
)
@ -1205,7 +1223,11 @@ def plugins():
plugins_internal += 1
return render_template(
"plugins.html", plugins=plugins, plugins_internal=plugins_internal, plugins_external=plugins_external, username=current_user.get_id(), dark_mode=app.config["DARK_MODE"], is_pro_version=PRO_VERSION, plugins_pro=PRO_PLUGINS_LIST
"plugins.html",
plugins=plugins,
plugins_internal=plugins_internal,
plugins_external=plugins_external,
username=current_user.get_id(),
)
@ -1369,15 +1391,12 @@ def custom_plugin(plugin: str):
return render_template(
Environment(loader=FileSystemLoader(join(sep, "usr", "share", "bunkerweb", "ui", "templates") + "/")).from_string(page.decode("utf-8")),
dark_mode=app.config["DARK_MODE"],
username=current_user.get_id(),
current_endpoint=plugin,
plugin=curr_plugin,
is_used=is_used,
is_metrics=is_metrics_on,
**app.jinja_env.globals,
is_pro_version=PRO_VERSION,
plugins_pro=PRO_PLUGINS_LIST,
)
module = db.get_plugin_actions(plugin)
@ -1448,16 +1467,13 @@ def cache():
)
],
username=current_user.get_id(),
dark_mode=app.config["DARK_MODE"],
is_pro_version=PRO_VERSION,
plugins_pro=PRO_PLUGINS_LIST,
)
@app.route("/logs", methods=["GET"])
@login_required
def logs():
return render_template("logs.html", instances=app.config["INSTANCES"].get_instances(), username=current_user.get_id(), dark_mode=app.config["DARK_MODE"], is_pro_version=PRO_VERSION, plugins_pro=PRO_PLUGINS_LIST)
return render_template("logs.html", instances=app.config["INSTANCES"].get_instances(), username=current_user.get_id())
@app.route("/logs/local", methods=["GET"])
@ -1703,7 +1719,12 @@ def reports():
top_code = ([k for k, v in codes.items() if v == max(codes.values())] or [""])[0]
return render_template(
"reports.html", reports=reports, total_reports=total_reports, top_code=top_code, top_reason=top_reason, username=current_user.get_id(), dark_mode=app.config["DARK_MODE"], is_pro_version=PRO_VERSION, plugins_pro=PRO_PLUGINS_LIST
"reports.html",
reports=reports,
total_reports=total_reports,
top_code=top_code,
top_reason=top_reason,
username=current_user.get_id(),
)
@ -1891,13 +1912,13 @@ def bans():
top_reason = ([k for k, v in reasons.items() if v == max(reasons.values())] or [""])[0]
return render_template("bans.html", bans=bans, top_reason=top_reason, username=current_user.get_id(), dark_mode=app.config["DARK_MODE"], is_pro_version=PRO_VERSION, plugins_pro=PRO_PLUGINS_LIST)
return render_template("bans.html", bans=bans, top_reason=top_reason, username=current_user.get_id())
@app.route("/jobs", methods=["GET"])
@login_required
def jobs():
return render_template("jobs.html", jobs=db.get_jobs(), jobs_errors=db.get_plugins_errors(), username=current_user.get_id(), dark_mode=app.config["DARK_MODE"], is_pro_version=PRO_VERSION, plugins_pro=PRO_PLUGINS_LIST)
return render_template("jobs.html", jobs=db.get_jobs(), jobs_errors=db.get_plugins_errors(), username=current_user.get_id())
@app.route("/jobs/download", methods=["GET"])

View file

@ -8,7 +8,7 @@
class="transition duration-300 text-xs tracking-wide leading-normal text-center text-white opacity-100 dark:text-white lg:text-left"
>
Copyright ©
<script>
<script nonce="{{ script_nonce }}">
document.write(new Date().getFullYear());
</script>
Bunkerity

View file

@ -17,42 +17,42 @@
<link rel="stylesheet" type="text/css" href="./css/plugins.css" />
<link rel="stylesheet" type="text/css" href="./css/dashboard.css" />
<script type="module" src="./js/global.js"></script>
<script src="./js/plugins/setup.js"></script>
<script type="module" src="./js/global.js" nonce="{{ script_nonce }}"></script>
<script src="./js/plugins/setup.js" nonce="{{ script_nonce }}"></script>
<script async src="./js/utils/purify/purify.min.js"></script>
<script src="./js/editor/ace.js"></script>
<script async src="./js/utils/purify/purify.min.js" nonce="{{ script_nonce }}"></script>
<script src="./js/editor/ace.js" nonce="{{ script_nonce }}"></script>
{% if current_endpoint == "global_config" %}
<script type="module" src="./js/global_config.js"></script>
<script type="module" src="./js/global_config.js" nonce="{{ script_nonce }}"></script>
{% elif current_endpoint == "configs" %}
<script type="module" src="./js/configs.js"></script>
<script type="module" src="./js/configs.js" nonce="{{ script_nonce }}"></script>
{% elif current_endpoint == "services" %}
<script type="module" src="./js/services.js"></script>
<script type="module" src="./js/services.js" nonce="{{ script_nonce }}"></script>
{% elif current_endpoint == "plugins" %}
<script type="module" src="./js/plugins.js"></script>
<script type="module" src="./js/plugins.js" nonce="{{ script_nonce }}"></script>
{% elif current_endpoint == "cache" %}
<script type="module" src="./js/cache.js"></script>
<script type="module" src="./js/cache.js" nonce="{{ script_nonce }}"></script>
{% elif current_endpoint == "logs" %}
<link rel="stylesheet" type="text/css" href="./css/flatpickr.css" />
<link rel="stylesheet" type="text/css" href="./css/flatpickr.dark.css" />
<script defer src="./js/utils/flatpickr.js"></script>
<script defer src="./js/logs.js"></script>
<script defer src="./js/utils/flatpickr.js" nonce="{{ script_nonce }}"></script>
<script defer src="./js/logs.js" nonce="{{ script_nonce }}"></script>
<link
rel="stylesheet"
type="text/css"
href="./css/datepicker-foundation.css"
/>
{% elif current_endpoint == "jobs" %}
<script type="module" src="./js/jobs.js"></script>
<script type="module" src="./js/jobs.js" nonce="{{ script_nonce }}"></script>
{% elif current_endpoint == "account" %}
<script type="module" src="./js/account.js"></script>
<script type="module" src="./js/account.js" nonce="{{ script_nonce }}"></script>
{% elif current_endpoint == "reports" %}
<script type="module" src="./js/reports.js"></script>
<script type="module" src="./js/reports.js" nonce="{{ script_nonce }}"></script>
{% elif current_endpoint == "bans" %}
<link rel="stylesheet" type="text/css" href="./css/flatpickr.css" />
<link rel="stylesheet" type="text/css" href="./css/flatpickr.dark.css" />
<script defer src="./js/utils/flatpickr.js"></script>
<script type="module" src="./js/bans.js"></script>
<script defer src="./js/utils/flatpickr.js" nonce="{{ script_nonce }}"></script>
<script type="module" src="./js/bans.js" nonce="{{ script_nonce }}"></script>
{% endif %}
</head>

View file

@ -32,7 +32,7 @@
</div>
</div>
</body>
<script>
<script nonce="{{ script_nonce }}">
//animation
const logoEl = document.querySelector("img");
setInterval(() => {

View file

@ -162,8 +162,8 @@
</main>
<!-- end particles -->
<!-- end content -->
<script src="js/tsparticles.bundle.min.js"></script>
<script>
<script src="js/tsparticles.bundle.min.js" nonce="{{ script_nonce }}"></script>
<script nonce="{{ script_nonce }}">
class Loader {
constructor() {
this.menuContainer = document.querySelector("[data-menu-container]");

View file

@ -385,7 +385,7 @@
</div>
<!-- end form -->
</main>
<script>
<script nonce="{{ script_nonce }}">
class ServerCheck {
constructor() {
this.servInp = document.querySelector("#server_name");

View file

@ -10,7 +10,7 @@
<link href="images/favicon.ico" rel="icon" type="image/x-icon" />
<link rel="stylesheet" href="css/dashboard.css" />
<link rel="stylesheet" href="css/login.css" />
<script defer src="./js/totp.js"></script>
<script defer src="./js/totp.js" nonce="{{ script_nonce }}"></script>
</head>
<body>
<div
@ -137,8 +137,8 @@
<div id="particles-js" class="login-img [&>*]:bg-primary"></div>
</div>
</main>
<script src="js/tsparticles.bundle.min.js"></script>
<script>
<script src="js/tsparticles.bundle.min.js" nonce="{{ script_nonce }}"></script>
<script nonce="{{ script_nonce }}">
class Loader {
constructor() {
this.menuContainer = document.querySelector("[data-menu-container]");