Basic guide to Content Security Policy with Rails
The basics of setting up CSP with your Rails app
This article will go through the basics of setting up a Content Security Policy (CSP) HTTP header for Rails apps. Your CSP defines what assets are permitted within your app, then by default everything else is disallowed. I won’t pretend to know the intricacies of CSP as I am a Rails developer and not a security expert. I am just going to outline the steps I followed to get CSP working on my Rails app.
What is a Content Security Policy?
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.
The above linked document also goes through how to set it up and what browsers it’s compatable with.
Scott Helme also has a great article all about CSP.
How do I set up a Content Security Policy with Rails?
This way of setting CSP was introduced in Rails 5.2 and it sits within
config > initializers > content_security_policy.rb.
Rails.application.config.content_security_policy do |policy|
policy.default_src :self, :https
policy.font_src :self, :https
policy.img_src :self, :https, :data, '*.s3.amazonaws.com'
policy.script_src :self, :unsafe_inline, '*.google-analytics.com', 'player.vimeo.com', '*.cloudflare.com'
policy.style_src :self, :https, :unsafe_inline, :unsafe_eval
policy.frame_src :self, '*.youtube.com', '*.vimeo.com'
# Specify URI for violation reports
# policy.report_uri "/csp-violation-report-endpoint"
default_srcThe fallback if the source isn’t defined
font_srcAllowed origin for fonts, the above example shows that we have the fonts within our app but you may have them from Google Fonts for example so you may require something like
policy.font_src :self 'fonts.gstatic.com'
img_srcAllowed origin for images. We have a combination of images contained within our app and images hosted on S3
object_srcWe allow no embedded content
script_srcAllowed origin for scripts i.e. Google Analytics
style_srcWe only allow styles from external files from the same origin
frame_srcAllowed iframes within the app i.e. if you allow YouTube iframes etc. this should be included here
report_uriYou can set up an endpoint for violation reports
How can I view my Content Security Policy?
If you want to see your CSP header in your app open up your web inspector. I use Google Chrome so I will navigate to the
Network tab. I then click on
Doc, refresh the page and click the name of the doc and then I can see the headers on the site. My CSP will be under the header
How do I test if I have the correct Content Security Policy?
To test it out I ran a local server and clicked through pages in my app. You should see if your fonts are rendering properly. Are embeds showing? Can you see images?
When setting up your CSP for the first time on production I would recommend setting another config variable in
Rails.application.config.content_security_policy_report_only = true.
This won’t apply the CSP headers when it is first deployed instead it will show you if there are any issues with your CSP in your web inspector in your console tab. This is a great tool to let you know whether there are any issues. If you deployed without doing this you run the risk of parts of the CSP not being properly set up so it may block parts of your app which will lead to a poor experience for users and potentially unhappy clients. Once you are happy that you have set up your CSP properly you just need to comment out or delete this line and redeploy.
How did we know we were missing a CSP?
As I say at the start of this article I’m no security expert and web development is a vast beast. Someone suggested the Security Headers website to us. Simply pop the URL you want to test in and it will let you know what security headers you’re missing.
Content Security Policy gotchas
When looking at your app you may think you know all the moving parts but if your clients have access to a CMS you may not be aware of all the sources of data within you app. Here are a few potential gotchas:
- other media embeds i.e. Soundcloud
- third party tools