Cloudfront: Adding HTTP security headers with Cloudfront Response Headers Policies

Enter a new era with Cloudfront Response Headers Policies

As of today Cloudfront Response Headers Policies are generally available in AWS. Looking through the launch blog

Let's try to add a new Reponse Headers Policy to a Cloudfront Distribution:

As a starting point I have already a cloudfront distribution with a custom error response for 403 error codes. The custom error code is required if your application hosted on Amazon s3 uses React or Angluar router. By default cloudfront will try to lookup the object in s3 e.g.: for /about it tries to find about.html object in s3. However we want it to go to /index.hml and use react router for routing to /about.

1.jpg

I also have a Cloudfront function that associated with my CF distribution from when I was testing it but it's not really required. Cloudfront Response Headers Policies can be used together with Cloudfront/Lambda@Edge function and are applied before them. Therefore, I decided to keep the CF function to test how it works. Now when I run curl on my CF distribution I get the current results:

# Curl on index.html security headers added by CF Function as expected
# Not relevant HTTP headers were redacted from the responses
$ curl -I https://d33vf9zl6um5ej.cloudfront.net/
HTTP/2 200
server: AmazonS3
content-security-policy: default-src 'self'
# Curl on object that doesn't exist on s3, no security header added
# by CF Function.
$ curl -I https://d33vf9zl6um5ej.cloudfront.net/sfdsfs
HTTP/2 200
server: AmazonS3

As you can see, Cloudfront Function adds the response security header only when object exists in the s3 origin. Therefore, security header is not added to the second response.

Let's check if adding Cloudfront Response Headers Policies(I will call it RHP from now) would help. I can associate an RHP with a Cloudfront distribution by clicking on the Behaviors tab and then clicking edit:

2.jpg There, I can see the available RHPs. Let's select SecurityHeadersPolicy that should add all the required security headers:

3.jpg

Next, let's save the changes to see if it actually helps with our security headers. Again let's use curl for testing:

# Not relevant HTTP headers were redacted from the responses
$ curl -I https://d33vf9zl6um5ej.cloudfront.net/
HTTP/2 200
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
strict-transport-security: max-age=3153600
content-security-policy: default-src 'self'

$ curl -I https://d33vf9zl6um5ej.cloudfront.net/sfdsfs
HTTP/2 200
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
strict-transport-security: max-age=3153600

We can see that the security headers are successfully added for both responses. However, as you can see the second response doesn't include the content-security-policy header. This happens because the managed SecurityHeadersPolicy leaves this header empty.

4.jpg

To fix this problem, I can simply create my own custom Security Headers Policy and assign it to my distribution. After doing that, I can finally get rid of the Cloudfront Function code because it's no longer needed!

Summary

It looks like AWS provided a really simple and intuitive way to add HTTP headers to Cloudfront responses/requests. It was very easy to setup Cloudfront Response Headers Policies and it even works in cases where CF functions don't work!

It was very productive week for me and this is my third blog post this week. If you liked the post please check two other posts: how to block access to certain aws regions and limit your blast radius and another post where I go through the differences between RDS read replicas and Multi-AZ deployments.

Did you find this article valuable?

Support Laurynas Tumosa by becoming a sponsor. Any amount is appreciated!