From 47396b52dea795548a22e71fe8e51a414c7d300d Mon Sep 17 00:00:00 2001 From: Nobuto Murata Date: Sat, 26 Aug 2017 20:12:43 +0700 Subject: [PATCH] Enable security related headers when SSL is enabled Horizon can be setup in a more secure way. Enable more headers: - X-XSS-Protection "1; mode=block" - X-Content-Type-Options "nosniff" - CSRF_COOKIE_SECURE, SESSION_COOKIE_SECURE in Django Change-Id: I84605bd7e00df64da522b805b4e9a88521d1e0f6 Partial-Bug: #1713202 --- hooks/horizon_utils.py | 4 +++- templates/default-ssl | 6 ++++-- templates/icehouse/local_settings.py | 5 +++++ templates/liberty/local_settings.py | 5 +++++ templates/mitaka/local_settings.py | 5 +++++ templates/newton/local_settings.py | 5 +++++ templates/ocata/local_settings.py | 5 +++++ unit_tests/test_horizon_utils.py | 3 ++- 8 files changed, 34 insertions(+), 4 deletions(-) diff --git a/hooks/horizon_utils.py b/hooks/horizon_utils.py index e94ac8d3..4718e196 100644 --- a/hooks/horizon_utils.py +++ b/hooks/horizon_utils.py @@ -132,7 +132,8 @@ CONFIG_FILES = OrderedDict([ 'hook_contexts': [horizon_contexts.HorizonContext(), horizon_contexts.IdentityServiceContext(), context.SyslogContext(), - horizon_contexts.LocalSettingsContext()], + horizon_contexts.LocalSettingsContext(), + horizon_contexts.ApacheSSLContext()], 'services': ['apache2', 'memcached'] }), (APACHE_CONF, { @@ -264,6 +265,7 @@ def enable_ssl(): subprocess.call(['a2ensite', 'default-ssl']) subprocess.call(['a2enmod', 'ssl']) subprocess.call(['a2enmod', 'rewrite']) + subprocess.call(['a2enmod', 'headers']) def determine_packages(): diff --git a/templates/default-ssl b/templates/default-ssl index 868d9ccd..08ed57aa 100644 --- a/templates/default-ssl +++ b/templates/default-ssl @@ -31,12 +31,14 @@ SSLProtocol +TLSv1 +TLSv1.1 +TLSv1.2 SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM {% if ssl_configured %} - SSLCertificateFile {{ ssl_cert }} - SSLCertificateKeyFile {{ ssl_key }} + SSLCertificateFile {{ ssl_cert }} + SSLCertificateKeyFile {{ ssl_key }} {% else %} SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key {% endif %} + Header set X-XSS-Protection "1; mode=block" + Header set X-Content-Type-Options "nosniff" SSLOptions +StdEnvVars diff --git a/templates/icehouse/local_settings.py b/templates/icehouse/local_settings.py index f45295ea..fac7e3a5 100644 --- a/templates/icehouse/local_settings.py +++ b/templates/icehouse/local_settings.py @@ -28,6 +28,11 @@ TEMPLATE_DEBUG = DEBUG # settings to better secure the cookies from security exploits #CSRF_COOKIE_SECURE = True #SESSION_COOKIE_SECURE = True +{% if ssl_configured %} +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True +{% endif %} + # Overrides for OpenStack API versions. Use this setting to force the # OpenStack dashboard to use a specfic API version for a given service API. diff --git a/templates/liberty/local_settings.py b/templates/liberty/local_settings.py index f147ff74..2a87c304 100644 --- a/templates/liberty/local_settings.py +++ b/templates/liberty/local_settings.py @@ -46,6 +46,11 @@ WEBROOT = '/' # settings to better secure the cookies from security exploits #CSRF_COOKIE_SECURE = True #SESSION_COOKIE_SECURE = True +{% if ssl_configured %} +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True +{% endif %} + # Overrides for OpenStack API versions. Use this setting to force the # OpenStack dashboard to use a specific API version for a given service API. diff --git a/templates/mitaka/local_settings.py b/templates/mitaka/local_settings.py index 0c5e6716..70bd15c9 100644 --- a/templates/mitaka/local_settings.py +++ b/templates/mitaka/local_settings.py @@ -45,6 +45,11 @@ WEBROOT = '/' # settings to better secure the cookies from security exploits #CSRF_COOKIE_SECURE = True #SESSION_COOKIE_SECURE = True +{% if ssl_configured %} +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True +{% endif %} + # The absolute path to the directory where message files are collected. # The message file must have a .json file extension. When the user logins to diff --git a/templates/newton/local_settings.py b/templates/newton/local_settings.py index 94ba0c02..eb9481ff 100644 --- a/templates/newton/local_settings.py +++ b/templates/newton/local_settings.py @@ -45,6 +45,11 @@ WEBROOT = '/' # settings to better secure the cookies from security exploits #CSRF_COOKIE_SECURE = True #SESSION_COOKIE_SECURE = True +{% if ssl_configured %} +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True +{% endif %} + # The absolute path to the directory where message files are collected. # The message file must have a .json file extension. When the user logins to diff --git a/templates/ocata/local_settings.py b/templates/ocata/local_settings.py index daa6f1c3..a20093b5 100644 --- a/templates/ocata/local_settings.py +++ b/templates/ocata/local_settings.py @@ -45,6 +45,11 @@ WEBROOT = '/' # settings to better secure the cookies from security exploits #CSRF_COOKIE_SECURE = True #SESSION_COOKIE_SECURE = True +{% if ssl_configured %} +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True +{% endif %} + # The absolute path to the directory where message files are collected. # The message file must have a .json file extension. When the user logins to diff --git a/unit_tests/test_horizon_utils.py b/unit_tests/test_horizon_utils.py index d40ca0eb..443ae74a 100644 --- a/unit_tests/test_horizon_utils.py +++ b/unit_tests/test_horizon_utils.py @@ -81,7 +81,8 @@ class TestHorizohorizon_utils(CharmTestCase): _call.assert_has_calls([ call(['a2ensite', 'default-ssl']), call(['a2enmod', 'ssl']), - call(['a2enmod', 'rewrite']) + call(['a2enmod', 'rewrite']), + call(['a2enmod', 'headers']) ]) def test_restart_map(self):