← Back to home

CloudFront Security Headers — Pattern

Two options: (A) CloudFront Response Headers Policy (easiest) or (B) a CloudFront Function for full control.

A) Response Headers Policy (recommended start)

Create a policy once and attach it to your distribution’s Behaviors. Suggested values:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline';
Referrer-Policy: strict-origin-when-cross-origin
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Permissions-Policy: geolocation=(), microphone=(), camera=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin

Note: page uses inline CSS, so CSP includes 'unsafe-inline' for style-src. If you move styles to a static CSS file later, you can tighten CSP.

B) CloudFront Function (fine-grained control)

Attach as a Viewer Response function on the behavior serving HTML.

function handler(event) {
  var resp = event.response;
  var h = resp.headers;

  h['strict-transport-security'] = {value: 'max-age=63072000; includeSubDomains; preload'};
  h['content-security-policy']   = {value: "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'"};
  h['referrer-policy']           = {value: 'strict-origin-when-cross-origin'};
  h['x-content-type-options']    = {value: 'nosniff'};
  h['x-frame-options']           = {value: 'DENY'};
  h['permissions-policy']        = {value: 'geolocation=(), microphone=(), camera=()'};
  h['cross-origin-opener-policy']= {value: 'same-origin'};
  h['cross-origin-resource-policy']= {value: 'same-origin'};

  return resp;
}

For non-HTML (PNG/CSS/JS), you can optionally attach the same function or let the Response Headers Policy apply globally.

Deploy notes