From faa54e2bb5ee452a47675c9c7c4d92e5badc3a17 Mon Sep 17 00:00:00 2001 From: Hanne Moa Date: Wed, 21 Feb 2024 13:03:13 +0100 Subject: [PATCH] Add CSP: frame-ancestors support --- python/nav/django/settings.py | 2 ++ python/nav/web/security.py | 23 +++++++++++++++++++++++ requirements/base.txt | 1 + 3 files changed, 26 insertions(+) diff --git a/python/nav/django/settings.py b/python/nav/django/settings.py index e628b3157f..61dfee2f0c 100644 --- a/python/nav/django/settings.py +++ b/python/nav/django/settings.py @@ -127,6 +127,7 @@ # Middleware MIDDLEWARE = ( 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'csp.middleware.CSPMiddleware', 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'nav.web.auth.middleware.AuthenticationMiddleware', @@ -269,6 +270,7 @@ _needs_tls = bool(_websecurity_config.getboolean('needs_tls')) SESSION_COOKIE_SECURE = _needs_tls X_FRAME_OPTIONS = _websecurity_config.get_x_frame_options() +CSP_FRAME_ANCESTORS = _websecurity_config.get_frame_ancestors() # Hack for hackers to use features like debug_toolbar etc. # https://code.djangoproject.com/wiki/SplitSettings (Rob Golding's method) diff --git a/python/nav/web/security.py b/python/nav/web/security.py index 21a43ac968..06a0c1b5a5 100644 --- a/python/nav/web/security.py +++ b/python/nav/web/security.py @@ -25,3 +25,26 @@ def get_x_frame_options(self): if frames_flag == 'none': return 'DENY' return 'SAMEORIGIN' + + def get_frame_ancestors(self): + """Return a list of sources + + A single 'none' or a string of one or more of self, source-scheme and + host-scheme are valid. There is currently no validator for host-scheme, + so source-scheme and host-scheme are both outputted as-is. + + To be set in django settings and used by the django-csp middleware. + """ + default = "'self'" + frames_flag = self.get(self.FRAMES_OPTION) or self.FRAMES_DEFAULT + pieces = frames_flag.split() + valid_pieces = [] + for piece in pieces: + if piece == 'none': + valid_pieces.append("'none'") + break + if piece == 'self': + valid_pieces.append(default) + else: + valid_pieces.append(piece) + return valid_pieces or [default] diff --git a/requirements/base.txt b/requirements/base.txt index 6a949e456d..3f543f34b8 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -24,6 +24,7 @@ dnspython<3.0.0,>=2.1.0 django-filter>=2 djangorestframework>=3.12,<3.13 django-crispy-forms>=1.8,<1.9 +django-csp crispy-forms-foundation>=0.7,<0.8 # REST framework