This is an automated email from the ASF dual-hosted git repository. gcruz pushed a commit to branch gc/8470 in repository https://gitbox.apache.org/repos/asf/allura.git
commit 01bf7f342c8e32d7f6c4d84eb63296f7da00df9c Author: Guillermo Cruz <[email protected]> AuthorDate: Wed Sep 28 11:21:10 2022 -0600 [#8470] added default csp headers and configurable options to add additional frame-src and form-action --- Allura/allura/config/middleware.py | 4 +++- Allura/allura/lib/app_globals.py | 24 ++++++++++++++++++++++++ Allura/allura/lib/custom_middleware.py | 26 ++++++++++++++++++++++++++ Allura/development.ini | 10 ++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Allura/allura/config/middleware.py b/Allura/allura/config/middleware.py index e5ace854a..2d759c4d8 100644 --- a/Allura/allura/config/middleware.py +++ b/Allura/allura/config/middleware.py @@ -63,6 +63,7 @@ from allura.lib.custom_middleware import LoginRedirectMiddleware from allura.lib.custom_middleware import RememberLoginMiddleware from allura.lib.custom_middleware import SetRequestHostFromConfig from allura.lib.custom_middleware import MingTaskSessionSetupMiddleware +from allura.lib.custom_middleware import ContentSecurityPolicyMiddleware from allura.lib import helpers as h from allura.lib.utils import configure_ming @@ -142,7 +143,8 @@ def _make_core_app(root, global_conf, full_stack=True, **app_conf): Middleware = mw_ep.load() if getattr(Middleware, 'when', 'inner') == 'inner': app = Middleware(app, config) - + # CSP headers + app = ContentSecurityPolicyMiddleware(app, config) # Required for sessions app = SessionMiddleware(app, config, data_serializer=BeakerPickleSerializerWithLatin1()) # Handle "Remember me" functionality diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py index 65279bbca..2f3ccc8fc 100644 --- a/Allura/allura/lib/app_globals.py +++ b/Allura/allura/lib/app_globals.py @@ -662,6 +662,30 @@ class Globals: def commit_statuses_enabled(self): return asbool(config['scm.commit_statuses']) + @property + def csp_report_mode(self): + if config.get('csp.report_mode'): + return asbool(config['csp.report_mode']) + return False + + @property + def csp_frame_sources(self): + if config.get('csp.frame_sources'): + return aslist(config['csp.frame_sources'], sep=',') + return None + + @property + def csp_form_action_urls(self): + if config.get('csp.form_action_urls'): + return aslist(config['csp.form_action_urls'], sep=',') + return None + + @property + def csp_report_uri(self): + if config.get('csp.report_uri'): + return config['csp.report_uri'] + return None + class Icon: def __init__(self, css, title=None): diff --git a/Allura/allura/lib/custom_middleware.py b/Allura/allura/lib/custom_middleware.py index ca97111f0..688bff4e8 100644 --- a/Allura/allura/lib/custom_middleware.py +++ b/Allura/allura/lib/custom_middleware.py @@ -35,6 +35,7 @@ from allura.lib import helpers as h from allura.lib.utils import is_ajax from allura import model as M import allura.model.repository +from tg import tmpl_context as c, app_globals as g log = logging.getLogger(__name__) @@ -455,3 +456,28 @@ class MingTaskSessionSetupMiddleware: # this is sufficient to ensure an ODM session is always established session(M.MonQTask).impl return self.app(environ, start_response) + + +class ContentSecurityPolicyMiddleware: + ''' Sets Content-Security-Policy headers ''' + + def __init__(self, app, config): + self.app = app + self.config = config + + def __call__(self, environ, start_response): + req = Request(environ) + resp = req.get_response(self.app) + resp.headers.add('Content-Security-Policy', "object-src 'none'") + resp.headers.add('Content-Security-Policy', 'upgrade-insecure-requests') + report_uri = '' + report_suffix = '' + if g.csp_report_mode and g.csp_report_uri: + report_suffix = '-Report-Only' + report_uri = f'; report-uri {g.csp_report_uri}' + if g.csp_frame_sources: + resp.headers.add(f'Content-Security-Policy{report_suffix}', f"frame-src 'self' {' '.join(g.csp_frame_sources)}{report_uri}") + if g.csp_form_action_urls: + resp.headers.add(f'Content-Security-Policy{report_suffix}', f"form-action 'self' {' '.join(g.csp_form_action_urls)}{report_uri}") + + return resp(environ, start_response) diff --git a/Allura/development.ini b/Allura/development.ini index 2a13baef9..361a9ad79 100644 --- a/Allura/development.ini +++ b/Allura/development.ini @@ -658,6 +658,16 @@ userstats.count_lines_of_code = true ; Minutes to cache saved search "bins" numbers. 0 will disable entirely, so caches are permanent ;forgetracker.bin_cache_expire = 60 +; CSP Headers +; enable report mode +; csp.report_mode = false +; csp.report_uri = + +; frame-src list of valid sources for loading frames +; csp.frame_sources = + +; form-action valid sources that can be used as an HTML <form> action +; csp.form_action_urls = ; ; Settings for comment reactions
