Here are two quick wins for security that will help you sleep better at night:
- If you are running Rails 5.2 or higher, chances are you are already using the new Content-Security-Policy feature for Cross-Site-Scripting (XSS) protection, it just needs configuring.
- The Rack-attack gem for throttling spammy clients, and preventing brute-force login attacks.
Both of these are quick to get started with, but will benefit from monitoring and fine tuning.
1. Content-Security-Policy (CSP)
Added to core Rails in the 5.2 release, the Content-Security-Policy DSL adds an HTTP header in your response that defines rules for the users' browser. If you have an earlier version of Rails, you can use the SecureHeaders gem.
“CSP is a great way to reduce or completely remove Cross-Site-Scripting (XSS) vulnerabilities. That would wipe out the number 1 web app security problem. Why? Because an effective CSP disallows inline scripts. It only allows scripts in separate files from trusted sources.” - quote by Heiko Webers, author of the Rails Security Guide.
“our ever evolving use of Content Security Policy (CSP) … is our single most effective mitigation…[against] content injection.” - quote from Github Engineering: GitHub’s CSP journey
Here is an example CSP HTTP Header:
Content-Security-Policy-Report-Only: default-src https:
You can get a good introduction by Matt Ferderer here: What is CSP? Why & How to Add it to Your Website
Rails 5.2 adds a CSP initializer like this:
# config/initializers/content_security_policy.rb
Rails.application.config.content_security_policy do |p|
p.default_src :self, :https
p.font_src :self, :https, :data
p.img_src :self, :https, :data
p.object_src :none
p.script_src :self, :https
p.style_src :self, :https, :unsafe_inline
# Specify URI for violation reports
p.report_uri "/csp-violation-report-endpoint"
end
The CSP reference is here: MDN web docs
Heiko Webers has written an excellent introduction to CSP in Rails
which will guide you
through configuring and tweeking your config/initializers/content_security_policy.rb
To set up the report_uri “/csp-violation-report-endpoint”, you can use this generator:
$ rails g scaffold csp_report blocked_uri:string disposition:string
document_uri:string effective_directive:string violated_directive:string
referrer:string status_code:integer raw_report :jsonb raw_browser:string
Heiko provides an example Controller create method, and several example
config/initializers/content_security_policy.rb
configurations, depending
on how appropriately arranged your Rails app is - from legacy through to a
perfectly organized app.
Once that is all in place you need to experiment with tightening the CSP, usually hand in hand with some refactoring of your javascript and CSS assets.
To see how you are doing, you can paste your CSP from your browser header into Google’s CSP Evaluator
Then once in production you should generally keep an eye on violations added to your report_uri end point.
For further reading, see GitHub’s CSP journey
2. The Rack-attack gem
Heiko Webers actually recommends the Rack-attack gem for the report_uri end point that could get legitimately hammered as you evolve your CSP. It would be a shame if your efforts to keep your site safe from content injection took your site down!
- For a general introduction: Rack::Attack: Rate limits against DDoS and abusive users
- Rack-attack on github: kickstarter/rack-attack
This example configuration from the github wiki is a great way to get started: Example Configuration:
“If you just go ahead and copy this to /config/initializers/rack_attack.rb, then you’ll be safe from 95% of bad requests. This won’t stop sophisticated hackers, but at least you can sleep more soundly knowing that your application isn’t going to be accidentally taken down by a misconfigured web scraper in the middle of the night.”
To conclude
Security is an ongoing effort. While configuring CSP HTTP Headers and adding rate-limiting capability aren’t silver bullets, they are important additions to your overall security arsenal.