diff --git a/template-deploy.yaml b/template-deploy.yaml index 2866382..d7aba70 100644 --- a/template-deploy.yaml +++ b/template-deploy.yaml @@ -104,7 +104,32 @@ Resources: Name: !Sub '${AWS::StackName}-security-headers' SecurityHeadersConfig: ContentSecurityPolicy: - ContentSecurityPolicy: "default-src 'self'; style-src 'self'; script-src 'self' 'wasm-unsafe-eval'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'" + ContentSecurityPolicy: "default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'" + Override: true + ContentTypeOptions: + Override: true + FrameOptions: + FrameOption: DENY + Override: true + ReferrerPolicy: + ReferrerPolicy: strict-origin-when-cross-origin + Override: true + StrictTransportSecurity: + AccessControlMaxAgeSec: 63072000 + IncludeSubdomains: true + Preload: true + Override: true + + MollierSecurityHeadersPolicy: + Type: AWS::CloudFront::ResponseHeadersPolicy + Properties: + ResponseHeadersPolicyConfig: + Name: !Sub '${AWS::StackName}-mollier-security-headers' + SecurityHeadersConfig: + ContentSecurityPolicy: + # CoolProp's Emscripten browser bundle uses both WebAssembly + # compilation and JavaScript's Function constructor. + ContentSecurityPolicy: "default-src 'self'; style-src 'self'; script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'" Override: true ContentTypeOptions: Override: true @@ -146,6 +171,14 @@ Resources: CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 ResponseHeadersPolicyId: !Ref SecurityHeadersPolicy CacheBehaviors: + - PathPattern: /mollier/* + TargetOriginId: site + ViewerProtocolPolicy: redirect-to-https + AllowedMethods: [GET, HEAD, OPTIONS] + CachedMethods: [GET, HEAD, OPTIONS] + Compress: true + CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 + ResponseHeadersPolicyId: !Ref MollierSecurityHeadersPolicy - PathPattern: /api/* TargetOriginId: api ViewerProtocolPolicy: https-only diff --git a/tests_verified/test_security_headers.py b/tests_verified/test_security_headers.py new file mode 100644 index 0000000..612cf22 --- /dev/null +++ b/tests_verified/test_security_headers.py @@ -0,0 +1,17 @@ +from pathlib import Path + + +TEMPLATE = (Path(__file__).parents[1] / "template-deploy.yaml").read_text(encoding="utf-8") + + +def test_unsafe_eval_is_scoped_to_mollier_policy(): + assert TEMPLATE.count("'unsafe-eval'") == 1 + assert "MollierSecurityHeadersPolicy:" in TEMPLATE + assert "PathPattern: /mollier/*" in TEMPLATE + assert "ResponseHeadersPolicyId: !Ref MollierSecurityHeadersPolicy" in TEMPLATE + + +def test_default_policy_does_not_allow_dynamic_code_execution(): + default_policy = TEMPLATE.split("MollierSecurityHeadersPolicy:", maxsplit=1)[0] + assert "'unsafe-eval'" not in default_policy + assert "'wasm-unsafe-eval'" not in default_policy