security headers static site

How to add Security Headers to an AWS S3 static website

I’ve created a couple posts in the past on how to create a static website using AWS S3 bucket and Cloudfront and using S3 with Cloudflare. Recently I’ve been getting more questions on how to add security response headers to an AWS S3 static website.

If you’re not familiar with security headers, basically security headers is another layer used to protect your websites. has a good article here is a good article on many of the popular security header types. You’ll also want to check out to easily check the security headers of your own site too.

With that, lets see how to add these security headers to your own static website.

How to add security headers using AWS Cloudfront

In the past, adding security headers in AWS required using AWS Lambda and adding a function to each request. However, AWS very recently made this process much easier with Cloudfront Policies. AWS also has a couple managed policies that make this even easier, or you can create your own.

  • To view the managed polices or create your own, first log into AWS and go to Cloudfront > Policies > Response Headers.
    aws cloudfront response policies
  • The existing policy called “SecurityHeadersPolicy” is a great starting point for most any website:
    aws managed securityheaderspolicy
    This policy should be a starting point and note this doesn’t set a Content-Security-Policy at all.
  1. To create your own policy click on “Create response headers policy”
    aws create response-headers-policy
  2. Give the new policy a name, description and then enable the headers you want set. I’d recommend turning on each of the security headers. Using the info from the article mentioned earlier at and the feedback from you can set your own custom headers. Then click on Create.
    aws create response headers
  3. Now with an AWS managed policy or your own custom policy ready to go, lets add it to your AWS Cloudfront distribution by going to Cloudfront > Distributions > [Your distribution] > and Behaviors then click on EDIT.
  4. Then under “Response headers policy” select the AWS managed policy or your newly created policy and then click on “Save Changed”.:
    aws cloudfront response headers policy
  5. Finally wait a few moments for the AWS Cloudfront distribution to finish updating.

That’s it for static sites using AWS Cloudfront, the only thing left to do is to check your site on to ensure the new security headers are working as expected.

How to add security headers using Cloudflare Workers

If your static website uses S3 with Cloudflare. then this process is for you. To add security headers in Cloudflare we need to utilize Cloudflare Workers. Cloudflare Workers are similar to AWS Lambda in the way they both host event-driven applications. But don’t let that scare you, this will be painless. ;)

  1. First log into your Cloudflare account and click on Workers and choose a subdomain name to be created under on Cloudflare:
    cloudflare workers subdomain
  2. Select your Workers plan, in this case the Free plan will work just fine.
    cloudflare workers plan
  3. Click on Create a Service.
    cloudflare create a service
  4. Now give your new service a name, I called mine “secureheaders” and then select “HTTP handler” as the starter.
    cloudflare service name
  5. On the Resources tab click on “Quick Edit“.
    cloudflare workers quick edit
  6. Now you need to add some code to the worker so that it will add the headers you want. Cloudflare provides an example code here, or you can copy and paste the code below which includes some edits to the Cloudflare example. Mostly un-commenting additional security headers as well as removing the TLS version check as I already enable TLS version control in Cloudflare.
        "Content-Security-Policy": "upgrade-insecure-requests",
        "Strict-Transport-Security" : "max-age=63072000; includeSubDomains; preload",
        "Permissions-Policy": "interest-cohort=()",
        "X-XSS-Protection": "1; mode=block",
        "X-Frame-Options": "DENY",
        "X-Content-Type-Options": "nosniff",
        "Referrer-Policy": "strict-origin-when-cross-origin",
    const BLOCKED_HEADERS = [
    addEventListener('fetch', event => {
    async function addHeaders(req) {
        let response = await fetch(req)
        let newHeaders = new Headers(response.headers)
        // This sets the headers for HTML responses: 
        if (newHeaders.has("Content-Type") && !newHeaders.get("Content-Type").includes("text/html")) {
            return new Response(response.body, {
                status: response.status,
                statusText: response.statusText,
                headers: newHeaders
        Object.keys(DEFAULT_SECURITY_HEADERS).map(function (name) {
            newHeaders.set(name, DEFAULT_SECURITY_HEADERS[name]);
        BLOCKED_HEADERS.forEach(function (name) {
        return new Response(response.body, {
            status: response.status,
            statusText: response.statusText,
            headers: newHeaders
  7. After you copy and paste the code, click on “Save and Deploy
    cloudflare save and deploy
  8. Now we need to add a route to our new Cloudflare Worker so that it applies the code to the main domain name. So go to the Triggers tab and then click on Add Route.
    cloudflare add route
  9. Now you need to add ONE of the two routes, either: ** OR*. If your site uses www then you’ll want the first option and if you don’t use www or other subdomains then the second option would be your pick. Then click on Add Route.
    cloudflare route path
  10. You’re done! Now the only thing left to do is to head over to and check out the new headers on your site.

Similar Posts