From eccce7e5397b1d67e2602694e53a4b4a7264ad50 Mon Sep 17 00:00:00 2001 From: Stefan Hacker Date: Sat, 6 Jun 2026 16:25:32 +0200 Subject: [PATCH] F-15/F-16/F-17 Security-Header & Logout - F-15 CSRF-Logout: /logout nur noch via POST mit CSRF-Token; Sidebar-Link ist jetzt ein POST-Formular. Schuetzt vor Cross-Site-Logout (SameSite=Lax greift bei Top-Level-GET nicht). - F-16 SRI: Subresource-Integrity-Hashes (sha384) + crossorigin fuer alle CDN-Ressourcen (Bootstrap CSS/JS, Bootstrap-Icons). - F-17: Permissions-Policy-Header (deaktiviert ungenutzte Browser-Features). Co-Authored-By: Claude Opus 4.8 (1M context) --- app/main.py | 6 +++++- app/static/css/app.css | 1 + app/templates/base.html | 18 ++++++++++++------ app/templates/error.html | 3 ++- app/templates/login.html | 6 ++++-- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/app/main.py b/app/main.py index df8f5ae..536e349 100644 --- a/app/main.py +++ b/app/main.py @@ -56,6 +56,10 @@ def _security_headers(resp): resp.headers['X-Frame-Options'] = 'DENY' resp.headers['X-Content-Type-Options'] = 'nosniff' resp.headers['Referrer-Policy'] = 'no-referrer' + resp.headers['Permissions-Policy'] = ( + 'geolocation=(), camera=(), microphone=(), payment=(), usb=(), ' + 'accelerometer=(), gyroscope=(), magnetometer=()' + ) resp.headers.setdefault('Content-Security-Policy', CSP) # HTML-Seiten (Formulare/Session-Daten) nicht cachen lassen. if resp.mimetype == 'text/html': @@ -262,7 +266,7 @@ def login(): return render_template('login.html') -@app.route('/logout') +@app.route('/logout', methods=['POST']) def logout(): session.clear() return redirect(url_for('login')) diff --git a/app/static/css/app.css b/app/static/css/app.css index ae8312d..25565be 100644 --- a/app/static/css/app.css +++ b/app/static/css/app.css @@ -13,6 +13,7 @@ body { background: #f4f6f9; min-height: 100vh; } background: var(--sidebar-hover); color: #fff; } #sidebar .nav-link i { width: 1.3em; } +#sidebar button.nav-link { background: none; border: 0; width: 100%; text-align: left; cursor: pointer; } #sidebar hr { border-color: var(--sidebar-hover); } .main-content { flex: 1; padding: 2rem; min-width: 0; } .card { border: none; box-shadow: 0 1px 4px rgba(0,0,0,.08); } diff --git a/app/templates/base.html b/app/templates/base.html index 4b7d1c9..210add2 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -5,8 +5,10 @@ {% block title %}DynDNS Manager{% endblock %} - - + + @@ -32,9 +34,12 @@

{{ session.admin_username }} - - Abmelden - +
+ + +
@@ -51,7 +56,8 @@ {% block content %}{% endblock %} - + {% block scripts %}{% endblock %} diff --git a/app/templates/error.html b/app/templates/error.html index 872f467..5901621 100644 --- a/app/templates/error.html +++ b/app/templates/error.html @@ -5,7 +5,8 @@ {{ code }} — DynDNS Manager - + diff --git a/app/templates/login.html b/app/templates/login.html index e2d8b50..01a014b 100644 --- a/app/templates/login.html +++ b/app/templates/login.html @@ -5,8 +5,10 @@ Login — DynDNS Manager - - + +