What is a content security policy?
From Mozilla Developer Network:
Content Security Policy (CSP) 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 malware distribution.
Although using a static web site usually means you have to worry less about security, the big picture is a bit more complicated. I embed many
<iframe> elements due to necessity. Bandcamp, Soundcloud, Spotify and YouTube, to name them all. Some of these embeds are generating awful code and tens of third-party scripts.
I could have sandboxed the iframes, but I wanted a more tight way to protect the entire website. Enter content security policy (CSP).
Implementing CSP on Netlify
In the past, using WordPress, I had to work on the Apache configuration to configure a web server to return the Content-Security-Policy HTTP header. The
<meta> element can be used to configure a policy. For example:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
After the switch to Jekyll and Netlify the process is significantly simplified. I just created a specific
netlify.toml configuration file in my repository and added the instructions.
https://webmention.io, which pulls in all the mentions including avatar images. For this specific case, in the
Content-Security-Policy section I had to allow:
img-src 'self' https://webmention.io https://*.amazonaws.com;
The main difficulty about the aforementioned audio-visual embeds was connected to their habit of injecting inline CSS, which I decided to disallow. The fix came from forcing their iframes to print specific classes based on my inclusion method in Jekyll, and move the third-party inline CSS to my SASS theme.
Bandcamp comes with a fixed dimension
iframe, depending on a few options when choosing the embed code on their site. Once I’d decided to always use the small version of the album picture, the main difference is the object height. I have three cases:
- Single song
- 2-song EP
I turned their fixed height in two specific embed classes:
<div class="iframe-bandcamp my-5 bc-single"> [...] <div class="iframe-bandcamp my-5 bc-ep"> [...] <div class="iframe-bandcamp my-5 bc-album">
Note that in Bandcamp, whenever I have more than one song, I always check “Show tracklist”:
Embed options in Bandcamp
Here is my security policy, which grants an
x-frame-options, from being embedded in an
[[headers]] for = "/*" [headers.values] X-Frame-Options = "deny" X-XSS-Protection = "1; mode=block" X-Content-Type-Options = "nosniff" Referrer-Policy = "no-referrer" Strict-Transport-Security = ''' max-age=31536000; includeSubDomains; preload ''' Content-Security-Policy = ''' default-src 'self' https://webmention.io; style-src 'self'; img-src 'self' https://webmention.io https://*.amazonaws.com; script-src 'self'; frame-src https://yewtu.be/embed/ https://www.youtube-nocookie.com/embed/ https://w.soundcloud.com/player/ https://bandcamp.com/EmbeddedPlayer/ ''' Permissions-Policy = ''' accelerometer=(none), ambient-light-sensor=(none), autoplay=(none), camera=(none), encrypted-media=(none), fullscreen=(none), geolocation=(none), gyroscope=(none), magnetometer=(none), microphone=(none), midi=(none), payment=(none), picture-in-picture=(none), speaker=(none), usb=(none), vibrate=(none), vr=(none) '''