From f25254f6d0a0aa5953bd8029a9e8a372c6cb8691 Mon Sep 17 00:00:00 2001 From: ilayda-cp Date: Fri, 6 Sep 2024 12:35:25 +0300 Subject: [PATCH] feat: add csp (#1993) * feat: add csp * feat: Add security headers --- webapp/handlers.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++ webapp/helpers.py | 8 +++++ 2 files changed, 82 insertions(+) diff --git a/webapp/handlers.py b/webapp/handlers.py index 14adffabc..0b1aaed97 100644 --- a/webapp/handlers.py +++ b/webapp/handlers.py @@ -15,6 +15,51 @@ from webapp import authentication, helpers +CSP = { + "default-src": ["'self'"], + "img-src": [ + "'self'", + "data: blob:", + "assets.ubuntu.com", + "res.cloudinary.com", + "api.charmhub.io", + "charmhub.io", + "*.cdn.snapcraftcontent.com", + "www.googletagmanager.com", + ], + "script-src-elem": [ + "'self'", + "assets.ubuntu.com", + "www.googletagmanager.com", + "*.crazyegg.com", + "w.usabilla.com", + # This is necessary for Google Tag Manager to function properly. + "'unsafe-inline'", + ], + "font-src": [ + "'self'", + "assets.ubuntu.com", + ], + "script-src": [ + "'self'", + "blob:", + "'unsafe-eval'", + "'unsafe-hashes'", + ], + "connect-src": [ + "'self'", + "sentry.is.canonical.com", + "*.crazyegg.com", + ], + "frame-src": [ + "'self'", + ], + "style-src": [ + "'self'", + "'unsafe-inline'", + ], +} + def charmhub_utility_processor(): """ @@ -87,3 +132,32 @@ def handle_store_api_error(e): ), status_code, ) + + @app.after_request + def add_headers(response): + """ + Security headers to add to all requests + - Content-Security-Policy: Restrict resources (e.g., JavaScript, CSS, + Images) and URLs + - Referrer-Policy: Limit referrer data for security while preserving + full referrer for same-origin requests + - Cross-Origin-Embedder-Policy: allows embedding cross-origin + resources without credentials + - Cross-Origin-Opener-Policy: enable the page to open pop-ups while + maintaining same-origin policy + - Cross-Origin-Resource-Policy: allowing only same-origin requests to + access the resource + - X-Permitted-Cross-Domain-Policies: disallows cross-domain access to + resources + """ + response.headers["Content-Security-Policy"] = helpers.get_csp_as_str( + CSP + ) + response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin" + response.headers["Cross-Origin-Embedder-Policy"] = "credentialless" + response.headers["Cross-Origin-Opener-Policy"] = ( + "same-origin-allow-popups" + ) + response.headers["Cross-Origin-Resource-Policy"] = "same-site" + response.headers["X-Permitted-Cross-Domain-Policies"] = "none" + return response diff --git a/webapp/helpers.py b/webapp/helpers.py index e079bea1c..c959dab2b 100644 --- a/webapp/helpers.py +++ b/webapp/helpers.py @@ -151,3 +151,11 @@ def param_redirect_exec(req, make_response, redirect): response.set_cookie("param_redirect", "", expires=0) return response return None + + +def get_csp_as_str(csp={}): + csp_str = "" + for key, values in csp.items(): + csp_value = " ".join(values) + csp_str += f"{key} {csp_value}; " + return csp_str.strip()