Content Security Policy (CSP) Header not set
One of the warning messages produced by a ZAP run against 127.0.0.1 is that the "Content Security Policy (CSP) Header not set"
See #318
One way to set the CSP headers is to insert something like the following into src/moin/apps/frontend/views.py:
@frontend.after_request
def add_security_headers(resp):
resp.headers["Reporting-Endpoints"] = "csp-endpoint='http://127.0.0.1:5000/csp-report-url'"
resp.headers["Content-Security-Policy-Report-Only"] = "default-src http:; report-uri csp-report-url; report-to csp-endpoint;"
return resp
where the above needs work, pretty names, move headers to wikiconfig.py, do same/similar for admin views etc.
The first problem encountered from above is the browser tries to PUT a jason formatted report to csp-report-url resulting in a 404.
Adding a text item named csp-report-url eliminates the 404 and returns a 200, but the write fails silently in moin code with nothing updated. The silent failure is possible due to the contenttype of the browser post is application/csp-report.
See https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html,
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only,
google other sources
stuck!
When I add the deprecated report-uri format to apps/frontend/view.py:
@frontend.after_request
def add_security_headers(resp):
resp.headers["Content-Security-Policy-Report-Only"] = "default-src 'self'; report-uri https//127.0.0.1/csp-report-uriXXX;"
return resp
Then the Firefox browser creates 3 POST transactions (that fail on 403/404/500 with various tweaks). Chrome, Edge, and Opera do not create a POST tranaction.
When I add the report-to format to apps/frontend/view.py:
@frontend.after_request
def add_security_headers(resp):
resp.headers["Reporting-Endpoints"] = "csp-endpoint='https://--snip--/csp-report-urlQQQ'"
resp.headers["Content-Security-Policy-Report-Only"] = "default-src 'self'; report-to csp-endpoint;"
return resp
Then Firefox, Chrome, Edge, and Opera do not create a POST xaction. Going into Firefox about:config and setting dom.reporting.enabled to True has no effect on Firefox.
I think the goal is to create a "Content-Security-Policy" and add support for an incoming POST with a contenttype of either "application/csp-report" or "application/reports+json". A well-written Content-Security-Policy will create no POST transactions. Wiki admins may view the CSP reports and delete files should there be many long reports. Wiki admins can turn off CSP reporting in wikiconfig.py. Since most of the work is performed in the client-side browser there will be no performance hit.
I did a short test with Chromium version 131 on Ubuntu, adapted your template for report-uri above and added a route '/+cspreport/log'. This writes the report json to the server log.
As a result, there are 2 findings for the 'Home' item (the 'Welcome' page). The first log entry is:
INFO moin.apps.frontend.views 2024-12-17 22:13:28.247394 127.0.0.1 application/csp-report {'document-uri': 'http://localhost:5000/Home', 'referrer': 'http://localhost:5000/Home', 'violated-directive': 'style-src-attr', 'effective-directive': 'style-src-attr', 'original-policy': "default-src 'self'; report-uri +cspreport/log;", 'disposition': 'report', 'blocked-uri': 'inline', 'line-number': 392, 'source-file': 'http://localhost:5000/Home', 'status-code': 200, 'script-sample': ''}
Line 392 in the html source is
<div id="moin-options-for-javascript" style="display: none">
This is the changed code, partially copied from https://github.com/finalduty/csp-report-collector/blob/main/src/csp_report_collector.py:
diff --git a/src/moin/app.py b/src/moin/app.py
index 01d4c50b..de9e3dbe 100644
--- a/src/moin/app.py
+++ b/src/moin/app.py
@@ -294,7 +294,7 @@ def before_wiki():
"""
Setup environment for wiki requests, start timers.
"""
- if request and is_static_content(request.path):
+ if request and (is_static_content(request.path) or request.path == "+cspreport/log"):
logging.debug(f"skipping before_wiki for {request.path}")
return
diff --git a/src/moin/apps/frontend/views.py b/src/moin/apps/frontend/views.py
index 7baef9ac..63f7d93e 100644
--- a/src/moin/apps/frontend/views.py
+++ b/src/moin/apps/frontend/views.py
@@ -117,6 +117,14 @@ logging = log.getLogger(__name__)
jfu_server_lock = threading.Lock()
[email protected]_request
+def add_security_headers(resp):
+ resp.headers["Content-Security-Policy-Report-Only"] = (
+ "default-src 'self'; report-uri +cspreport/log;"
+ )
+ return resp
+
+
@frontend.route("/+dispatch", methods=["GET"])
def dispatch():
args = request.values.to_dict()
@@ -285,6 +293,21 @@ def lookup():
return Response(html, status)
[email protected]("/+cspreport/log", methods=["POST"])
+def cspreport():
+ """
+ csp report receiver
+ """
+ logging.info("got CSP report.")
+ if request.content_type != "application/csp-report":
+ abort(400, f"Invalid content type. Expected 'application/csp-report', got '{request.content_type}'.")
+
+ csp_report = json.loads(request.data.decode("UTF-8"))["csp-report"]
+ logging.info(f"{datetime.now()} {request.remote_addr} {request.content_type} {csp_report}")
+ logging.info("got CSP report.")
+ return Response("", 204)
+
+
def _compute_item_transclusions(item_name):
"""Compute which items are transcluded into item <item_name>.
The report-uri above will fail for any namespace other than 'default'.
@UlrichB22 Thanks, that is much better.
Assuming you agree moin should have CSP headers, would you finish this issue? Seems I have many busy days with no time for moin lately.
I can try, but will also need some time. It will be a simple solution with standard logging and a limit of messages per hour or day to avoid spamming in the logs. Maybe you can help with testing afterwards as I can only test browsers on Linux :wink:
Thanks, will be ready to help.
So far Chrome, Opera, and Edge are consistent in the sequence of the cspreport fields, Firefox outputs a different sequence.
There are 3 CSP warnings when viewing http://127.0.0.1:5000/help-en/MoinWikiMacros. All are caused by xstatic-FontAwesome.
Addition CSP warnings are caused by xstatic-jquery. Newer release is available.
I will work on templates/slideshow.html and move the script into a new separate java-script file.
The moinwiki_in.py converter allows many attributes that result in HTML style attributes.
https://github.com/moinwiki/moin/blob/0541b1c8b3d46fcc8641d3f2b46d7689d65736be/src/moin/converters/moinwiki_in.py#L965-L992
A PR replacing these attributes in some help-en elements will follow shortly.
How should these attributes be handled in general? Should we disable/ disallow them or just issue a warning when a user adds style attributes? I have also seen many items in a moin1.9 wiki that use them.