Content Security Policy

What is Content Security Policy

Content Security Policy (CSP) is an HTTP response header that gets sent from the server and it tells the browser approved sources of content that the browser can load. It is an easy and effective way to prevent Cross Site Scripting (XSS) attacks. It is supported by all common browsers (Full Table).

Why Use Content Security Policy

When a browser loads a web page there are a lot of pieces that it loads, such as images, scripts, fonts, and CSS. Using my blog as an example, all the content like pictures, posts, and the majority of scripts are local. There are a couple elements that are not hosted locally, such as some scripts and the font are loaded from Disqus for comments and Google for the font. Your browser has no way of knowing what is good to load and what is bad to load, so it just loads everything whether it is from blog.jwhite.network or malicioussite.com. By adding a CSP header, you can tell the browser that loading elements from blog.jwhite.network are fine, but anything else is bad to load.
 

Defining a Content Security Policy

There are 14 directives and policy is made up of one or more directives.

DirectivesDefinitions
default-srcDefault policy that is applied to all elements if they are not set.
script-srcValid sources for javascript.
style-srcValid sources for stylesheets.
img-srcValid sources for images.
connect-srcValid sources for ajax, WebSocket or EvenSource.
font-srcValid sources for fonts.
object-srcValid sources of plugins like <object> or <embed>.
media-srcValid sources of <audio> or <video>.
sandboxEnables sandbox for request's resources.
report-uriTells the browser to make POST reports of policy failures.
child-srcDefines valid source for web works and elements such as <frame> and <iframe>.
form-actionsValid sources for <form>.
frame-ancestorsValid sources for <frame>, <iframe>, <object>, <embed>, and <applet>.
plugin-typesDefines valid MIME types for plugins invoked via <object> and <embed>.

The directives and what they define, courtesy of Content-Security-Policy.com.
Each one of those directives that ends in src supports a list of values called the source list. Multiple source list values can be used apart from 'none' which is used as the only value.

Source ValueDescription
*Wildcard. Allows for all URLs, but not data:
'none'Denies resources from all sources.
'self'Allows resources from the same origin (has to match scheme, host, and port).
data:Allows resources via the data scheme
sub.example.comAllows resources from specified domain name
*.example.comAllows resources from any subdomain under example.com
https://example.comAllows resources to be loaded only with HTTPS matching the domain.
https:Allows resources to be loaded only with HTTPS on any domain.
'unsafe-inline'Allows use of inline elements.
'unsafe-eval'Allows use of unsafe dynamic code evaluations.
'nonce-'Allows script or style tag to execute if the nonce matches the header value.
'sha256-'Allows script or style to execute if it matches the hash.

Using Content Security Policy

A simple CSP would be:
default-src 'self'; img-src *; script-src https://userscripts.example.com
This policy allows anything to be loaded from itself with the default-src set to self. It allows images to be allowed from anywhere. Javascript can only come from https://userscripts.example.com. Items like fonts and stylesheets would have to load from the host itself.

Limitations & Wrap up

CSP works on the idea of whitelisting origins, which means that using inline javascript or CSS is considered unsafe. I use Jekyll for my blog and theme that I have uses scss. What this means is that the styling is all loaded inline and you can see this if you inspect this pages and look in the <head> tag. There is <style> and it contains all the CSS for my blog. While not as bad as inline javascript, it is still better to avoid. It is something that I would like to fix.

Content Security Policy is a great way to defend against XSS attacks. It works by telling your browser to whitelist origins and blocking everything else. It is easy to implement a universally supported by browsers. It is definitely something to look setting up if you do not have it already.