Rails Security: above and beyond the defaults

This is a blog post version of the Rails Security talk that I gave at Rubyfuza 2017 in Cape Town earlier this year.

I'll also be giving this talk (or an updated version of it) for Ruby Dev Summit, a free online conference, in October this year.

Kisko Labs logo

If you don't know who I am, I'm a (primarily Ruby) developer at Kisko Labs.

Kisko is a small software consultancy based in Helsinki, Finland. We're heavily invested in Rails as it's our primary development tool so Rails is near and dear to our hearts.

Matias Korhonen

You can find me in all the usual places:

I start too many side projects

First some things you should know about me…

I tend to start too many side projects (and sometimes I even finish some of them)

Homebrew. No, not the package manager.

I brew beer as a hobby

beerstyles.co

To help with my brewing hobby, I build an iOS app for browsing BJCP Style Guidelines.

Download on the App Store

piranhas.co

I've also made Piranhas, a book price comparison app. It lets ou search for books on different stores and it calculates the shipping costs and currency conversions for you.

TLS.care

I'm also working on a product called TLS.care. It monitors your sites and alerts you if your SSL certificate is about to expire or if it has been revoked.

Disclaimers

This is the ass covering section

I'm not a cryptographer, not even an amateur one.

I'm not a hacker of any colour.

I'm just a developer who wants his apps to remain as secure as possible.

And with that out of the way, we can continue.

What is this talk (or blog post in this case) about?

Mostly generic web application security

Most of this is advice that will apply to any web app, regardless of what framework you're using. However, there are some Rails specific implementation suggestions as that's our primary tool at Kisko.

What sort of risks do we mostly deal with? Who is our adversary?

You might even be asking yourself “Why would anyone ever hack my website?”

Understand that the attacks affecting a large amount of web site owners … are predominantly automated

In fact it's likely that there won't be a person targeting you but rather it'll be a bot or script executing attacks against as many targets as possible.

It takes 30-45 days for a new website, with no content or audience, to be identified and added to a bot crawler

Automation gives attackers all the same advantages that it does elsewhere:

  • Mass exposure
  • Reduced overhead
  • Tools for everyone regardless of skill
  • Dramatically increased odds of success

“But there's nothing valuable on my site”

Some people might feel that their site doesn't have anything of value to anyone.

This is a sentiment that is almost universally wrong. All legitimate sites have at least once thing of value to malicious actors: reputation.

Your site's good reputation can be used to facilite malware installs, dodgy ads, or the attacker may simply choose to hold your site hostage.

At the end of the day, every site on the internet is a target to someone.

Rails

At Kisko we love Rails, it increases out productivity and let's us achieve great things for our clients in a shorter time than we could otherwise.

How does it fare security-wise?

Rails is a great base for a secure web application

We certainly think it's pretty swell…

Sane defaults

It comes with sane defaults (both in terms of security and otherwise).

You get countermeasures against CSRF, XSS, and injection attacks straight out of the box.

It sets sane security headers by default

It comes with support for securely stored sessions and passwords and encourages you to adopt good development practices.

In fact, you get all of this for “free” when you use Rails.

If you work with Rails, you should read the Ruby on Rails Security Guide.

Assuming that you've chosen Rails and are using all the security features that it supplies out of the box, what more can you do?

HTTPS

First of all, and perhaps most importantly, you should use HTTPS in production.

Why HTTPS?

I think we are well past the point where it's acceptable not to use HTTPS for production apps.

Our clients or users might not know to require it, but as experts we know better.

Even if you believe that your site “has nothing valuable”, do you trust every actor that might attempt to inject content onto your page?

Comcast and other ISPs are inserting their own ads and notifications into customers' data streams

This is happening, and it's being perpetrated by major ISPs in major countries. This is not some theoretical threat…

Google Investigation: ad injection is infesting millions of devices

Studies suggest that ad injection affects as many as 5% of browsers.

HTTPS doesn't just provide privacy and security, it also provides integrity

HTTPS increases the chances that what you serve ends up in front of the user, unmodified.

Both Chrome and Firefox now mark login pages as “Not Secure”.

This will soon be the case for all pages with forms on them!

Eventually, Chrome will show a Not Secure warning for all pages served over HTTP

And the plan is to gradually extend this to all pages served over plain HTTP.

And if that isn't enough, there are also technical reasons to use HTTPS. For example HTTP 2.0 is effectively HTTPS only and some advanced browser features require HTTPS.

Visitors to your site will blame you, not the shady ISP/hotspot

What's more, if some shady wifi hotspot injects ads or malware onto your site your users are going to blame you, not the network.

How?

Hopefully by now you'e conviced that you need HTTPS. So how do you get HTTPS for your site?

HTTPS: certificates

Anyone can get a free certificate from Let's Encrypt. If you use AWS, Amazon will issue your a free certificate for use on their services.

If you use Heroku, it already has support for automated certs from Let's Encrypt.

Let's Encrypt are also working on adding support for wildcard certs by January 2018

force_ssl is your friend

If you're using Rails, you should make sure you enable the force_ssl setting.

This redirects visitors to the HTTPS version of your site, enables Strict Transport Security (HSTS), and marks cookies as secure.

HSTS means that repeat visitors will automatically use HTTPS after the first visit.

Secure cookies are only sent over HTTPS, never plain HTTP.

On my test site everything seems fine and dandy using the Rails and Nginx defaults.

But is it?

That's good as far as it goes, but how can we check if the defaults are good enough?

Qualys SSL Labs: SSL Server Test

Luckily for us there's a really handy tool we can use: the SSL Labs server test

It's free and it does a great job of telling you were you might have gone wrong.

Server test grade: B

Well…

I mean it's not bad…

…but we can do better!

This server supports weak Diffie-Hellman (DH) key exchange parameters. Grade capped to B.

If you click “learn more” get to read interesting things about logjam and FREAK attacks, DHE_EXPORT ciphers, Elliptic-Curve Diffie-Hellman Key Exchange and prime numbers.

Luckily for us there's a shortcut.

People far smarter than me have created the Mozilla SSL configuration generator.

Pick your server and what browsers you're targeting and…

…and you get a good server configuration template.

(also known as magic security incantations)

TADA!

And once we deploy it to our test server…

Server test grade A+

An A+ is better than a B.

HSTS preload

If your site meets the technical requirements, you can submit it for inclusion in the HSTS preload list. This list is used by Chrome, Firefox, Opera, Safari, IE 11 and Edge.

The requirements are pretty straightforward, so it's not hard to meet them.

Content Security Policy

Moving on to content security policies.

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.

This is how MDN explains what a CSP is, personally I found that nigh incomprehensible.

A header which tells the browser where assets can be loaded from

My version is that it's a header which tells the browser where assets (scripts, stylesheets, fonts, and so on) can be loaded from.

Even IE supports it with an X- prefix.

CSP: Why?

A CSP header can be used to reduce the potential attack surface of your site.

Even with the fairly relaxed CSP that I'm forced to use on Piranhas, it's blocked some weird requests.

Here's a log of a script that was blocked from static.cmptch.com

And if you Google static.cmptch.com, you find some interesting results.

Shady search results about cmptch.com

I'm still not sure what or why some thing was trying to load this on my site, but I do know that I want no part of it.

Content Security Policies allow quite fine grained control over what can be loaded from where

CSP headers are set per-response, so different pages can have different levels of restrictions.

Content-Security-Policy: script-src 'self'

For example, you can only allow scripts from the same origin as the page itself.

Content-Security-Policy: script-src 'self' https://apis.google.com

Or allow same origin and apis.google.com

Available directives

There's a large variety of directive available for allowing/blocking scripts, images, fonts, and more.

Reporting

You can use the report-uri directive to get JSON reports on what's been blocked.

Free reporting andpoint and UI

Report URI is a handy free service for collecting the violation reports.

Screenshot of Report URI

That's where this screenshot you saw earlier came from…

Where to start?

How should you go about adding a CSP header to your site?

Adding a CSP header to a long standing site can be tricky because you have to figure where you're loading everything from. It's much easier if you're starting a new project

You might not even be aware of everything that's being loaded (Facebook buttons, YouTube embeds, analytics, and so forth).

A simple policy like this might be a good place to start and if you want more tooling…

… I recommend the SecureHeaders gem from Twitter.

It provides support for CSP headers (and a lot more) and it also provides support for overriding the policy on a controller or action level.

Going through everything in SecureHeaders is too much to cover in this talk…

The defaults are pretty sane (but more strict than the Rails defaults).

The defaults are mostly the same as the Rails defaults, with a couple of extras.

The CSP header, X-Download-Options (which mitigates some IE vulnerabilities), and X-Permitted-Cross-Domain-Policies which restricts Adobe Flash player’s access to data.

And here's the CSP header which didn't fit onto the previous slide…

Still afraid?

If this still sounds scary, there's also a safe way to experiment.

Content-Security-Policy-Report-Only

As the name suggests, like the normal header except that violations are not enforced, only reported. You can see the violations in console or via the report-uri.

This is also great if you're making changes to an existing policy.

CSP pro-tips slide

If you embark on the CSP road, here are my tips on how to proceed.

HTTP, HTTPS, CSP, SSL, TLS, XSS, and so forth

Even an incidental look into the work of security quickly lands you in a sea of alphabet soup.

HPKP

So here's one more: HPKP

What is HTTP Public Key Pinning and should you use it?

It's a security header that what public keys the browser will trust in the future.

Foot, meet gun

I feel that this is an excellent way to shoot yourself in the foot.

You can lock out your users if you're not careful.

Once it's propagated to your users' browser caches, the only recourse is waiting for it to expire.

My feeling is that it's not worth the pain, I'm not the only one.

For a more detailed look at the issues with HPKP, see this blog post by Scott Helme (the creator of Report URI): I'm giving up on HPKP

However

How ever if you're slightly crazy or work at an organization with the resources and discipline to handle it, here's a couple of tips.

In short: be very, very careful. Make backups keys and store them offline. You may also need to anticipate switching to a different key algorithm in the future.

Summary

Wrapping all of this up…

Rails is great and you should use HTTPS.

Using a CSP is not very difficult, especially if you have one from the very beginning.

Don't use HTTP Public Key Pinning unless you actually understand the risks involved.

Thanks

Ping me on Twitter if you have comments (or via email)