I'm having the same problem (using S3/CloudFront) and it appears there is currently no way to set this up easily.
S3 has a whitelist of the headers permitted, and Content-Security-Policy is not on it. Whilst it is true you can use the prefixed x-amz-meta-Content-Security-Policy, this is unhelpful as there is no browser support for it.
There are two options I can see.
1) you can serve the html content from a webserver on an EC2 instance and set that up as another CloudFront origin. Not really a great solution.
2) include the CSP as a meta tag within your html document:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src http://*.foobar.com 'self'">
...
This option is not as widely supported by browsers, but it appears to work with both Webkit and Firefox, so the current Chrome, Firefox, Safari (and IOS 7 Safari) seem to support it.
I chose 2 as it was the simpler/cheaper/faster solution and I hope AWS will add the CSP header in the future.
Answer from Ravenscar on Stack OverflowI'm having the same problem (using S3/CloudFront) and it appears there is currently no way to set this up easily.
S3 has a whitelist of the headers permitted, and Content-Security-Policy is not on it. Whilst it is true you can use the prefixed x-amz-meta-Content-Security-Policy, this is unhelpful as there is no browser support for it.
There are two options I can see.
1) you can serve the html content from a webserver on an EC2 instance and set that up as another CloudFront origin. Not really a great solution.
2) include the CSP as a meta tag within your html document:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src http://*.foobar.com 'self'">
...
This option is not as widely supported by browsers, but it appears to work with both Webkit and Firefox, so the current Chrome, Firefox, Safari (and IOS 7 Safari) seem to support it.
I chose 2 as it was the simpler/cheaper/faster solution and I hope AWS will add the CSP header in the future.
S3/CloudFront takes any headers that the origin set and forward those to the client, but you can't set custom headers on you response directly.
You can use Lambda@Edge function that can inject security headers through CloudFront.
Here is how the process works: (reference aws blog)
- Viewer navigates to website.
- Before CloudFront serves content from the cache it will trigger any Lambda function associated with the Viewer Request trigger for that behavior.
- CloudFront serves content from the cache if available, otherwise it goes to step 4.
- Only after CloudFront cache ‘Miss’, Origin Request trigger is fired for that behavior.
- S3 Origin returns content.
- After content is returned from S3 but before being cached in CloudFront, Origin Response trigger is fired.
- After content is cached in CloudFront, Viewer Response trigger is fired and is the final step before viewer receives content.
- Viewer receives content.
Below is the blog from aws on how to do this step by step.
https://aws.amazon.com/blogs/networking-and-content-delivery/adding-http-security-headers-using-lambdaedge-and-amazon-cloudfront/
I have been following an example from the cloudfront docs for setting up an s3 static site that uses cloudfront.
It works with the example content. But there's some problems when I upload my own static site content.
Basically, I have a static site generated by a tool called "quarto". It works if I deploy to a regular apache web server. But when I deploy the same content to s3+cloudfront, I see a bunch of CSP-related errors in the javascript console.
Visually, some fonts fall back to default values and also I see much of the javascript functionality doesn't work.
The types of errors I see are like this (it happens to be for math typesetting stuff, katex):
whatever-path/:1 Refused to load the script 'https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js' because it violates the following Content Security Policy directive: "script-src 'self'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.
I get 17 of them, all different, but all naming "Content Security Policy".
My very limited understanding is that is happening because I need to "whitelist" the hyperlinks of javascript libraries from other domains, for example, the one above: https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js
I see in the cloudfront console, under policies, there's a bunch of stuff related to origin request and response headers. It mentions CORS, which appears to be the same (or adjacent) concept to CSP. I haven't changed this from the default. I notice the example CF stack added some "security headers". Is this the place where I would need to make changes?
Is there a practical, straightforward approach for dealing with this? Or do I need to read and understand all aspects of website security before even attempting an s3 static site?
I should add that if I deploy the exact same static site to a lightsail instance I spun up that runs apache, it all works fine. The problem appears with s3+cloudfront.