Integrating Content Security Policy into your Rails applications

Content Security Policy CSP


Content Security Policy (CSP) is an HTTP response header that restricts the browser to loading external assets such as scripts, styles or media from a wide variety of sources — as well as inline scripts. It is intended to prevent wide categories of attacks, such as cross-site scripting (XSS), click-jacking and other forms of code injection. Content Security Policy is powerful because it prevents many common attacks that target your users’ browsers.

This protection ensures that assets of your application loaded by your customer’s browsers (e.g. JavaScript from Algolia for your search as a service, fonts from Google or images from your ad provider) are part of the white list defined in the Content Security Policy header.

Content Security Policy CSP explanationContent Security Policy overview

CSP is also useful to enforce HTTPs for all the resources of an application, preventing an insecure icon from appearing in the address bar of your website:

Website with mixed HTTP and HTTPS content

The fail: <1% of web apps are using CSP

CSP is simple, it should be easy to implement. In reality the situation is much more complex, and many great engineering teams have discussed the methods and processes they built internally to use CSP.

CSP is hard to implement without proper tooling for the following reasons:

  • An app’s dependencies are added and removed by many people within your team: developers rely on Sentry, marketers on Intercom, integrators add styles, fonts and images, and so on. Each time someone adds a new dependency without updating the policy, CSP is triggered and the website fails to load.
  • The CSP header is usually set by the server (e.g. Nginx or Apache), and managed by ops rather than by the developers who are usually adding new dependencies.
  • Errors occur client side (i.e. in the browser), and silently. Without proper tooling, there is no way to know whether your website is broken for some users. This is hard to debug.
  • The CSP recommendation defines a way for browsers to report policies to a specific endpoint, but this endpoint needs to be configured in the build process so that the team gets notified of any violations that occur and process it.

Any of these reasons is enough to explain why the adoption of CSP is so slow.

Ruby on Rails integration today

Many Ruby gems exist to help implement CSP in your Rails application, for instance the SecureHeaders gem.

Then, the policy needs to be written on your own. For example, the current GitHub content security policy is the following:

Of course, you may also need to distinguish the production policy from the staging policy in case you use different hosts.

On top of that, you’ll also want to use a custom service to watch the violations that will occur on your application. The ReportURI service does that, for instance, just adding one line to the policy in this way:

That’s a great technical help if you want to implement the policy by yourself. Yet, it won’t help you with the issues described above. When new violations are found — or if you need to add a new third party, you need to:

  • update the code describing the policy;
  • redeploy your application, everytime you need to update the policy;
  • be careful about the CSP semantics, errors can be quickly made.

The fix: integrating CSP in 30 seconds

The process

The virtuous CSP circle The virtuous CSP circle

Sqreen works inside your application. Sqreen suggests the most suitable Content Security Policy for your application, automatically updating your CSP headers with your approval.

Sqreen adds the proper « report only » headers to your app — which means that the browser won’t automatically block anything, but will still reports resources that would have broken the policy’s rules. These reports are sent directly to Sqreen — no need to configure anything. Since the policy defaults to report only mode, none of these violations will break the user experience — but will safely let Sqreen gather enough reports to craft the perfect policy.

The dashboard displays the count of reports triggered by your users. You can then choose which rules should be enforced, and which should be ignored. Your application gets notified of your modifications and is automatically updated with the new policy you have defined.

Content Security Policy Sqreen

As soon as no more violations are reported, the policy can be switched from report only to enforce. Browsers will then enforce the policy and block components violating the policy.

Later on you may wish to add other resources to your application (e.g. host content with a new CDN, add a new analytics package, start to use WebSockets, etc…). New dependencies will trigger reports as soon as the app is used with these other domains, and you will be immediately notified:

Slack notification CSPThe Sqreen dashboard and notifications are shown below:

Adding Content Security Policy to an application

What’s next?

Sqreen solves many challenges that engineering teams face using CSP. CSP is backwards-compatible by design, which makes Sqreen compatible with any browser.

CSPv2 and CSPv3 offer many new features, such as hash-usage, that allows for more control when white-listing inline scripts and sending more detailed reports.

We will soon support an API that will allow our customers to check if any violations occur within their CI pipeline.

CSP also allows fine-grained filtering based on paths, although we only provide host-level granularity so far.

CSPv3 defines the possibility of blocking insecure content on HTTPS pages, which prevent users from receiving warnings (check this for more details). It is so far only available in Chrome Canary, but may be added when available to more browsers.

Give us a shout if you want more details about Sqreen, and don’t forget to make your next coffee break productive 😉

Did you enjoy this article ? Help us spreading our vision and product recommending it below, or on Twitter. We are @SqreenIO.

Notify of
1 Comment
Newest Most Voted
Inline Feedbacks
View all comments