diff --git a/app/__init__.py b/app/__init__.py index 79899c5ca..c32f45ef5 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -496,17 +496,24 @@ def save_service_or_org_after_request(response): # https://www.owasp.org/index.php/List_of_useful_HTTP_headers def useful_headers_after_request(response): + notify_environment = os.environ['NOTIFY_ENVIRONMENT'] response.headers.add('X-Frame-Options', 'deny') response.headers.add('X-Content-Type-Options', 'nosniff') response.headers.add('X-XSS-Protection', '1; mode=block') response.headers.add('Content-Security-Policy', ( - "default-src 'self' 'unsafe-inline';" - "script-src 'self' *.google-analytics.com 'unsafe-inline' 'unsafe-eval' data:;" + "default-src 'self' {} 'unsafe-inline';" + "script-src 'self' {} *.google-analytics.com 'unsafe-inline' 'unsafe-eval' data:;" "connect-src 'self' *.google-analytics.com;" "object-src 'self';" - "font-src 'self' data:;" - "img-src 'self' *.google-analytics.com *.notifications.service.gov.uk {} data:;" - "frame-src 'self' www.youtube.com;".format(get_cdn_domain()) + "font-src 'self' {} data:;" + "img-src 'self' {} *.google-analytics.com *.notifications.service.gov.uk {} data:;" + "frame-src 'self' www.youtube.com;".format( + configs[notify_environment].ASSET_DOMAIN, + configs[notify_environment].ASSET_DOMAIN, + configs[notify_environment].ASSET_DOMAIN, + configs[notify_environment].ASSET_DOMAIN, + get_cdn_domain(), + ) )) if 'Cache-Control' in response.headers: del response.headers['Cache-Control'] diff --git a/app/config.py b/app/config.py index 2db0dfddb..202a4939c 100644 --- a/app/config.py +++ b/app/config.py @@ -74,6 +74,7 @@ class Config(object): REDIS_URL = os.environ.get('REDIS_URL') REDIS_ENABLED = os.environ.get('REDIS_ENABLED') == '1' + ASSET_DOMAIN = '' ASSET_PATH = '/static/' @@ -94,6 +95,8 @@ class Development(Config): ANTIVIRUS_API_HOST = 'http://localhost:6016' ANTIVIRUS_API_KEY = 'test-key' + ASSET_PATH = '/static/' + class Test(Development): DEBUG = True @@ -109,6 +112,8 @@ class Test(Development): ANTIVIRUS_API_HOST = 'https://test-antivirus' ANTIVIRUS_API_KEY = 'test-antivirus-secret' + ASSET_DOMAIN = 'static.example.com' + class Preview(Config): HTTP_PROTOCOL = 'https' @@ -119,6 +124,7 @@ class Preview(Config): MOU_BUCKET_NAME = 'notify.works-mou' NOTIFY_ENVIRONMENT = 'preview' CHECK_PROXY_HEADER = False + ASSET_DOMAIN = 'static.notify.works' ASSET_PATH = 'https://static.notify.works/' @@ -132,6 +138,7 @@ class Staging(Config): MOU_BUCKET_NAME = 'staging-notify.works-mou' NOTIFY_ENVIRONMENT = 'staging' CHECK_PROXY_HEADER = False + ASSET_DOMAIN = 'static.staging-notify.works' ASSET_PATH = 'https://static.staging-notify.works/' @@ -145,6 +152,7 @@ class Live(Config): MOU_BUCKET_NAME = 'notifications.service.gov.uk-mou' NOTIFY_ENVIRONMENT = 'live' CHECK_PROXY_HEADER = False + ASSET_DOMAIN = 'static.notifications.service.gov.uk' ASSET_PATH = 'https://static.notifications.service.gov.uk/' diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 73d7e2375..da3176d02 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -37,7 +37,7 @@ gulp.task('copy:govuk_template:css', () => gulp.src(paths.template + 'assets/sty })) .on('error', plugins.sass.logError) .pipe(plugins.cssUrlAdjuster({ - prependRelative: '/static/', + prependRelative: process.env.NOTIFY_ADMIN_ENVIRONMENT == 'config.Development' ? '/static/' : '/', })) .pipe(gulp.dest(paths.dist + 'stylesheets/')) ); diff --git a/tests/app/main/views/test_headers.py b/tests/app/main/views/test_headers.py index 1ef2a794c..95e2c8d8e 100644 --- a/tests/app/main/views/test_headers.py +++ b/tests/app/main/views/test_headers.py @@ -8,12 +8,13 @@ def test_owasp_useful_headers_set(client, mocker): assert response.headers['X-Content-Type-Options'] == 'nosniff' assert response.headers['X-XSS-Protection'] == '1; mode=block' assert response.headers['Content-Security-Policy'] == ( - "default-src 'self' 'unsafe-inline';" - "script-src 'self' *.google-analytics.com 'unsafe-inline' 'unsafe-eval' data:;" + "default-src 'self' static.example.com 'unsafe-inline';" + "script-src 'self' static.example.com *.google-analytics.com 'unsafe-inline' 'unsafe-eval' data:;" "connect-src 'self' *.google-analytics.com;" "object-src 'self';" - "font-src 'self' data:;" - "img-src 'self' *.google-analytics.com *.notifications.service.gov.uk static-logos.test.com data:;" + "font-src 'self' static.example.com data:;" + "img-src " + "'self' static.example.com *.google-analytics.com *.notifications.service.gov.uk static-logos.test.com data:;" "frame-src 'self' www.youtube.com;" ) @@ -25,11 +26,12 @@ def test_headers_non_ascii_characters_are_replaced(client, mocker): assert response.status_code == 200 assert response.headers['Content-Security-Policy'] == ( - "default-src 'self' 'unsafe-inline';" - "script-src 'self' *.google-analytics.com 'unsafe-inline' 'unsafe-eval' data:;" + "default-src 'self' static.example.com 'unsafe-inline';" + "script-src 'self' static.example.com *.google-analytics.com 'unsafe-inline' 'unsafe-eval' data:;" "connect-src 'self' *.google-analytics.com;" "object-src 'self';" - "font-src 'self' data:;" - "img-src 'self' *.google-analytics.com *.notifications.service.gov.uk static-logos??.test.com data:;" + "font-src 'self' static.example.com data:;" + "img-src " + "'self' static.example.com *.google-analytics.com *.notifications.service.gov.uk static-logos??.test.com data:;" "frame-src 'self' www.youtube.com;" )