Adding security response headers with Amazon CloudFront

Header

Background

Security response headers are HTTP headers that can be to improved the security posture of your web application and can mitigate attacks such as Cross-Site Scripting (XSS) which forms part of injection attacks in the OWASP Top 10 (number 3 at the time of writing this post).

Although this is a personal site, it’s been a while since I completed any updates so I wanted to baseline the config and then improve the security posture. This blog is fronted by Amazon CloudFront using Amazon S3 as an origin for the static content. This gives me a an opportunity to check out how easily CloudFront can help in adding controls

Benchmarking

I used Security Headers to scan the site. It’s a free, easy to use service where you stick in your site URL and it analyses the reponse headers before giving you a grading. Coincidently there was some news around Security Headers in June this year. It was created by Scott Helme, but is now part of Probely. Hopefully it continues to be maintained and basic services offered for free.

So, back to the scan, how back was it? Pretty bad, but that wasn’t really a surprise since apart from installing a certificate I’ve not focussed on the security previously. I got a resounding Fail (F)

Fail Result

What was more of a surprise was that with over 254 million sites scanned by Security Headers, 48% get a big fat F.

I’ve listed the missing headers below along with a brief description of each along with the OWASP recommended setting

Header Description OWASP Recommended Setting
Strict-Transport-Security The website tells browsers that it should only be accessed using HTTPS. Be careful when using this to ensure that your site does not have pages which can only be served by HTTP. The includeSubDomains is a flag which, if present, signals to the browser that the HSTS Policy applies to this HSTS server as well as any subdomains. max-age defines the time in seconds for which the web server should only deliver through HTTPS Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy Content Security Policy (CSP) is a security feature that is used to specify the origin of content that is allowed to be loaded on a website or in a web applications. It is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross-Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement to distribution of malware. Dependant on your site and the content you are serving. See MDN for more details
X-Frame-Options The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a <frame>, <iframe>, <embed> or <object>. Sites can use this to avoid clickjacking attacks, by ensuring that their content is not embedded into other sites. Not, Contact Security Policy (CSP) is the recommended way using the frame-ancestors directive if possible. X-Frame-Options: DENY
X-Content-Type-Options Used by the server to indicate to the browsers that the MIME types advertised in the Content-Type headers should be followed and not guessed. This header is used to block browsers’ MIME type sniffing X-Content-Type-Options: nosniff
Referrer-Policy Controls how much referrer information (sent via the Referer header) should be included with requests. Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy Controls which origins can use which browser features, both in the top-level page and in embedded frames. For every feature controlled by Feature Policy, the feature is only enabled in the current document or frame if its origin matches the allowed list of origins. This means that you can configure your site to never allow the camera or microphone to be activated. This prevents that an injection, for example an XSS, enables the camera, the microphone, or other browser feature. The recommended settings disables this functionality for all domains. Permissions-Policy: geolocation=(), camera=(), microphone=()

Implementing Response Header Policies with Amazon CloudFront

Now that I’ve got a good understand of headers I can add to improve the security of my site, I can get started. Amazon CloudFront offers the ability to modify the HTTP headers sent to your Origin (in this case Amazon S3) and in the responses it sends back to browsers. This can be used to simplify Origin request such as removing non relevant headers, but it can also be used to insert security headers using CloudFront’s Response Headers Policies. The policy can then be attached to your CloudFront Distribution behavior.

Thankfully AWS provide some managed policies which you can use to easily get started.

AWS Managed Policies

The managed policies can be a quick way of adding some default response headers, although I recommend you pay close attention to the header values to ensure they are relevant to your site. Attaching the “SecurityHeadersPolicy” and a re-scan on the Security Headers site moved me from an F to a B so in the right direction, but not much use if it’s not suited for the use case.

Security Headers Scan B

In order to dive deeper and personalise the reponse I need to create a custom response headers policy. You can do this using the AWS Console, Infrastructure as Code (IaC) tool of choice (Amazon CloudFormation, Terraform etc) or using the AWS CLI/API. In this instance I’ll use the AWS CLI to obtain and create a new policy.

The Amazon CloudFront includes the CLI Skeleton to generate a YAML file for the config which I can then use as a template to modify and upload with your policy config:

aws cloudfront create-response-headers-policy --generate-cli-skeleton yaml-input > response-headers-policy.yaml

Opening the YAML file in your IDE of choice we can then modify it to add and remove headers as required. Here’s an example file using my config. **Note: AWS do not current support the Permissions-Policy header out of the box. I’ve added it here as a custom header:

ResponseHeadersPolicyConfig:  
  Comment: 'implements security response headers'  
  Name: 'iceCandidate security reponse header policy' 
  SecurityHeadersConfig: 
    FrameOptions: 
      Override: true
      FrameOption: DENY 
    ReferrerPolicy: 
      Override: true  
      ReferrerPolicy: strict-origin-when-cross-origin 
    ContentTypeOptions: 
      Override: true  
    StrictTransportSecurity: 
      Override: true 
      IncludeSubdomains: true 
      Preload: true 
      AccessControlMaxAgeSec: 63072000 
  CustomHeadersConfig: 
    Quantity: 1
    Items: 
    - Header: 'Permissions-Policy'
      Value: 'geolocation=(), camera=(), microphone=()' 
      Override: true 

Note: I’ve not added a Content Security Policy as this needs to be done at a later date once I’ve understood which 3rd party dependencies I want to keep for this Hugo theme.

I can now upload my new response headers policy as a YAML file:

aws cloudfront create-response-headers-policy --cli-input-yaml file://response-headers-policy.yaml

The CLI response will provide a policy ID which I can then use to attach this new response headers policy to my CloudFront distribution. To do this I get the distribution config for my distribution ID and then update the ResponseHeadersPolicyId field to reflect my new policy ID along with updating the ETag field to IfMatch but without changing the value IfMatch: <ID>

aws cloudfront get-distribution-config --id distribution_ID --output yaml > dist-config.yaml

Then use the following command to update the distribution:

aws cloudfront update-distribution --id distribution_ID --cli-input-yaml file://dist-config.yaml

Final Steps

Now that the CloudFront distribution has been updated I can visit my site and use my browsers (Chrome) dev tools to ensure the response headers are updated when visiting the site.

Updated Headers

A visit back to Security Headers and a re-scan moves the site to an A rating which will soon be improved further once a CSP is added.

Security Headers Final Scan

Please let me know if this post has helped you or if you have any recommended updates.