Add support for Content-Security-Policy header
Adding a configuration parameter csp-options that, when set, adds a Content-Security-Policy header to the apache configuration. This header can prevent or minimize the risk of certain types of security threats by placing restrictions on the things the web page's code can do. Closes-Bug: #2118835 Change-Id: I06f0b1c2787fa56460e5a196d3ca07c0a85c14e3 Signed-off-by: Jorge Merlino <jorge.merlino@canonical.com>
This commit is contained in:
@@ -331,6 +331,13 @@ options:
|
||||
.
|
||||
For this option to have an effect, SSL must be configured and
|
||||
enforce-ssl option must be true.
|
||||
csp-options:
|
||||
type: string
|
||||
default: "frame-ancestors 'self'; form-action 'self';"
|
||||
description: |
|
||||
Options for the CSP (Content Security Policy) header. This header allows to
|
||||
control which resources the user agent is allowed to load. For more details
|
||||
on CSP refer to: https://developer.mozilla.org/docs/Web/HTTP/Guides/CSP
|
||||
database-user:
|
||||
type: string
|
||||
default: horizon
|
||||
|
@@ -345,6 +345,7 @@ class ApacheContext(OSContextGenerator):
|
||||
'enforce_ssl': False,
|
||||
'hsts_max_age_seconds': config('hsts-max-age-seconds'),
|
||||
"custom_theme": config('custom-theme'),
|
||||
'csp_options': config('csp-options'),
|
||||
}
|
||||
|
||||
if config('enforce-ssl'):
|
||||
|
@@ -37,4 +37,7 @@
|
||||
KeepAliveTimeout 75
|
||||
MaxKeepAliveRequests 1000
|
||||
Header set X-Frame-Options: "sameorigin"
|
||||
{% if csp_options %}
|
||||
Header set Content-Security-Policy "{{ csp_options }}"
|
||||
{% endif %}
|
||||
</VirtualHost>
|
||||
|
@@ -52,6 +52,9 @@ NameVirtualHost *:{{ 443 }}
|
||||
Header set Strict-Transport-Security "max-age={{ hsts_max_age_seconds }}"
|
||||
# NOTE(ajkavanagh) due to Bug 1853173 the cookie can't be secure at this time, so disabling until a fix is found.
|
||||
# Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
|
||||
{% endif %}
|
||||
{% if csp_options %}
|
||||
Header set Content-Security-Policy "{{ csp_options }}"
|
||||
{% endif %}
|
||||
Header set X-XSS-Protection "1; mode=block"
|
||||
Header set X-Content-Type-Options "nosniff"
|
||||
|
@@ -74,39 +74,68 @@ class TestHorizonContexts(CharmTestCase):
|
||||
self.pwgen.return_value = "secret"
|
||||
|
||||
def test_Apachecontext(self):
|
||||
self.assertEqual(horizon_contexts.ApacheContext()(),
|
||||
{'http_port': 70, 'https_port': 433,
|
||||
'enforce_ssl': False,
|
||||
'hsts_max_age_seconds': 0,
|
||||
'custom_theme': False})
|
||||
self.assertEqual(
|
||||
horizon_contexts.ApacheContext()(),
|
||||
{'http_port': 70, 'https_port': 433,
|
||||
'enforce_ssl': False,
|
||||
'hsts_max_age_seconds': 0,
|
||||
'csp_options': "frame-ancestors 'self'; form-action 'self';",
|
||||
'custom_theme': False},
|
||||
)
|
||||
|
||||
def test_Apachecontext_enforce_ssl(self):
|
||||
self.test_config.set('enforce-ssl', True)
|
||||
self.https.return_value = True
|
||||
self.assertEqual(horizon_contexts.ApacheContext()(),
|
||||
{'http_port': 70, 'https_port': 433,
|
||||
'enforce_ssl': True,
|
||||
'hsts_max_age_seconds': 0,
|
||||
'custom_theme': False})
|
||||
self.assertEqual(
|
||||
horizon_contexts.ApacheContext()(),
|
||||
{'http_port': 70, 'https_port': 433,
|
||||
'enforce_ssl': True,
|
||||
'hsts_max_age_seconds': 0,
|
||||
'csp_options': "frame-ancestors 'self'; form-action 'self';",
|
||||
'custom_theme': False},
|
||||
)
|
||||
|
||||
def test_Apachecontext_enforce_ssl_no_cert(self):
|
||||
self.test_config.set('enforce-ssl', True)
|
||||
self.https.return_value = False
|
||||
self.assertEqual(horizon_contexts.ApacheContext()(),
|
||||
{'http_port': 70, 'https_port': 433,
|
||||
'enforce_ssl': False,
|
||||
'hsts_max_age_seconds': 0,
|
||||
'custom_theme': False})
|
||||
self.assertEqual(
|
||||
horizon_contexts.ApacheContext()(),
|
||||
{'http_port': 70, 'https_port': 433,
|
||||
'enforce_ssl': False,
|
||||
'hsts_max_age_seconds': 0,
|
||||
'csp_options': "frame-ancestors 'self'; form-action 'self';",
|
||||
'custom_theme': False},
|
||||
)
|
||||
|
||||
def test_Apachecontext_hsts_max_age_seconds(self):
|
||||
self.test_config.set('enforce-ssl', True)
|
||||
self.https.return_value = True
|
||||
self.test_config.set('hsts-max-age-seconds', 15768000)
|
||||
self.assertEqual(horizon_contexts.ApacheContext()(),
|
||||
{'http_port': 70, 'https_port': 433,
|
||||
'enforce_ssl': True,
|
||||
'hsts_max_age_seconds': 15768000,
|
||||
'custom_theme': False})
|
||||
self.assertEqual(
|
||||
horizon_contexts.ApacheContext()(),
|
||||
{'http_port': 70, 'https_port': 433,
|
||||
'enforce_ssl': True,
|
||||
'hsts_max_age_seconds': 15768000,
|
||||
'csp_options': "frame-ancestors 'self'; form-action 'self';",
|
||||
'custom_theme': False},
|
||||
)
|
||||
|
||||
def test_Apachecontext_csp_options(self):
|
||||
self.https.return_value = True
|
||||
self.test_config.set(
|
||||
'csp-options',
|
||||
"default-src https: 'unsafe-eval'; object-src 'none'",
|
||||
)
|
||||
self.assertEqual(
|
||||
horizon_contexts.ApacheContext()(),
|
||||
{'http_port': 70,
|
||||
'https_port': 433,
|
||||
'enforce_ssl': False,
|
||||
'hsts_max_age_seconds': 0,
|
||||
'csp_options':
|
||||
"default-src https: 'unsafe-eval'; object-src 'none'",
|
||||
'custom_theme': False},
|
||||
)
|
||||
|
||||
def test_HorizonContext_defaults(self):
|
||||
self.assertEqual(horizon_contexts.HorizonContext()(),
|
||||
|
Reference in New Issue
Block a user