Rails and Content Security Policies

Preview:

Citation preview

Ruby Brigade 10/2016

Rails and Content Security Policies

Who am I?• A developer at Kisko Labs

• In my free 8me I work on too many side projects

• piranhas.co — a book price comparison site and app

• Beer Styles — an iOS app for browsing beer style guidelines

• TLS.caresoon! — an SSL/TLS cer8ficate monitoring service

• and I also brew beer

Kisko LabsWe build and launch tools on the web

Are you a Ruby or frontend developer? We're hiring

CSPContent Security Policy

Content Security Policy is an added layer of security that helps to detect

and mi3gate certain types of a5acks, including Cross Site

Scrip3ng (XSS) and data injec3on a5acks.

— MDN

Content Security Policy: a header which tells the browser where

resources (scripts, stylesheets, fonts, etc) can be loaded from.

— Me

Supported by all major browsers,even Internet Explorer (kind of)

CSP: Why?• Reduces the poten.al surface area for a3acks or malicious

injec.on of scripts

• Prevents malicious browser extensions and malware from inser.ng crap into your pages.

• For example, the CSP on Piranhas.co has stopped some shady browser extensions from injec.ng ads? onto the page.

https://static.cmptch.com

I don't know what this is, but I know that I don't want it on my site!

CSP Direc*ves

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

For example, you can allow scripts from a domain but not images (or vice versa).

Or, for example, if you allow users to upload images, but not scripts, you can segregate user uploads to a specific host (“allow images from uploads.example.com but nothing else”).

Available direc,ves

• default-src: Define loading policy for all resources type in case of a resource type dedicated direc5ve is not defined (fallback),

• script-src: Define which scripts the protected resource can execute,

• object-src: Define from where the protected resource can load plugins,

• style-src: Define which styles (CSS) the user applies to the protected resource,

• img-src: Define from where the protected resource can load images,

• media-src: Define from where the protected resource can load video and audio,

• frame-src: Define from where the protected resource can embed frames,

• font-src: Define from where the protected resource can load fonts,

• connect-src: Define which URIs the protected resource can load using script interfaces,

• form-ac-on: Define which URIs can be used as the ac;on of HTML form elements,

• sandbox: Specifies an HTML sandbox policy that the user agent applies to the protected resource,

• script-nonce: Define script execu;on by requiring the presence of the specified nonce on script elements,

• plugin-types: Define the set of plugins that can be invoked by the protected resource by limi:ng the types of resources that can be embedded,

• reflected-xss: Instructs a user agent to ac:vate or deac:vate any heuris:cs used to filter or block reflected cross-site scrip:ng a?acks, equivalent to the effects of the non-standard X-XSS-Protec:on header,

• report-uri: Specifies a URI to which the user agent sends reports about policy viola:on

Adding a CSP header to a long standing site can be … tricky

CSP example (piranhas.co)Content-Security-Policy: default-src https:; style-src 'unsafe-inline' https://cdn.piranhas.xyz https://fonts.googleapis.com; script-src 'unsafe-inline' 'unsafe-eval' https://cdn.piranhas.xyz https://www.google-analytics.com https://suggestqueries.google.com https://www.googleapis.com; img-src data: https:; report-uri https://x.report-uri.io/r/default/csp/enforce;

(line breaks added for clarity…)

Adding it from the very beginning is a lot easier…

CSP example (simplified)

Content-Security-Policy: default-src *;

Allow all sources, but disallow unsafe inline assets (for example scripts and styles).

CSP example (simplified alterna3ve)

Content-Security-Policy: default-src 'self';

Allow all sources, but disallow unsafe inline assets (for example scripts and styles).

'unsafe-inline' vs “safe inline”• By default inline scripts are blocked

• You can either

• add 'unsafe-inline' to your CSP (in which case you're back where your started)

• or use inline scripts with a nonce (more on this later)

In cryptography, a nonce is an arbitrary number that may only be

used once.— Wikipedia

You specify the nonce in the CSP header:

Content-Security-Policy: ... script-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;

and in your <script> (or <style>) tag:

<script nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI="> console.log("Hello World")</script>

The browser will allow each nonce to be used only once…

Secure Headers

Secure Headers

A Rack middleware gem from Twi2er which adds support for more security headers than are available by default in Rails.

• h#ps://github.com/twi#er/secureheaders

• h#ps://rubygems.org/gems/secure_headers

Makes it easier to use CSP headers (and it also handles other security headers)

Secure Headers

It lets you define an app-wide CSP that you can override or append to at a controller or ac9on level.

Don't just add it though. Look through the configura6on and understand what it's doing. You might want to disable some of the op6ons.

Secure Headers

It's a pre*y extensive library, so read the README to learn more.

Secure Headers: nonces

It also includes support for safe inline styles and scripts using nonces.

For example:

<%= nonced_javascript_tag do %> console.log("nonced!");<% end %>

Secure Headers: nonces

Generates this HTML:

<script nonce="/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=">console.log("nonced!")</script>

And adds this to the CSP header:

Content-Security-Policy: ... script-src 'nonce-/jRAxuLJsDXAxqhNBB7gg7h55KETtDQBXe4ZL+xIXwI=' ...;

Secure Headers: minimal configura3on

# config/initializers/secure_headers.rbSecureHeaders::Configuration.default do |config| config.csp = { default_src: %w(*), upgrade_insecure_requests: Rails.env.production?, # see https://www.w3.org/TR/upgrade-insecure-requests/ report_uri: %w(https://x.report-uri.io/r/default/csp/enforce) }

config.hpkp = SecureHeaders::OPT_OUTend

Or you might want to use 'self' instead of *

Secure Headers

Rails also sets some of the same security headers, but Secure Headers has code to override those with its own configura;on.

=> Secure Headers knows how to play nice with Rails

=> Secure Headers knows how to play nice with Rails

isolate_namespace SecureHeaders if defined? isolate_namespace # rails 3.0conflicting_headers = ['X-Frame-Options', 'X-XSS-Protection', 'X-Permitted-Cross-Domain-Policies', 'X-Download-Options', 'X-Content-Type-Options', 'Strict-Transport-Security', 'Content-Security-Policy', 'Content-Security-Policy-Report-Only', 'Public-Key-Pins', 'Public-Key-Pins-Report-Only', 'Referrer-Policy']

# ...

conflicting_headers.each do |header| Rails.application.config.action_dispatch.default_headers.delete(header)end

h"ps://github.com/twi"er/secureheaders/blob/v3.4.1/lib/secure_headers/rail;e.rb

CSP pro-)ps

CSP pro-)ps

Start by using the Content-Security-Policy-Report-Only header to test and tweak your CSP header in the wild.

Content-Security-Policy-Report-Only: default-src *, report-uri https://x.report-uri.io/r/default/csp/enforce;;

Deploy the Report Only header for a few days before star1ng to enforce it.

CSP pro-)ps• New projects

• Enforce the CSP from the beginning

• Report viola<ons from your staging or produc<on environment

• Old projects

• Add a CSP with all the sources you think you need

• Deploy it as Report Only, leave it for a week or two to uncover anything you might have forgoEen about

• Deploy the enforced policy once you've accounted for all the viola<ons

• Both

• When making changes, you may wish to first test them with the Report Only header (depending on the change)

CSP resources• h#ps://github.com/twi#er/secureheaders

• h#ps://security.googleblog.com/2016/09/reshaping-web-defenses-with-strict.html

• CSP Evaluator: h#ps://csp-evaluator.withgoogle.com/

• CSP MiGgator: h#ps://chrome.google.com/webstore/detail/csp-miGgator/gijlobangojajlbodabkpjpheeeokhfa

Summary

Summary• Rails defaults are pre/y good, but can be (fairly easily) be 9ghtened

• Use a Content Security Policy, if only to prevent ad/malware injec9on by compromised browsers

• The more strict the CSP is, the fewer chances there are for third par9es to mess with your site

• Use the Secure Headers gem to manage the CSP policy and other security headers

• It requires more thought than the Rails defaults, but I think it's worth it

• Excep&on to all of the above: If you're working on your first Rails app, you probably shouldn't add this complexity.

Thanks

Ma#as Korhonen@ma$askorhonen

ma#askorhonen.fi

piranhas.co

Beer Styles

TLS.caresoon!

Recommended