Rails 5.2 DSL for configuring Content Security Policy

Sushant Mittal

By Sushant Mittal

on October 23, 2018

This blog is part of our  Rails 5.2 series.

Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate various types of attacks on our web applications, including Cross Site Scripting (XSS) and data injection attacks.

What is XSS ?

In this attack, victim's browser may execute malicious scripts because browser trusts the source of the content even when it's not coming from the correct source.

Here is our blog on XSS written sometime back.

How CSP can be used to mitigate and report this attack ?

By using CSP, we can specify domains that are valid sources of executable scripts. Then a browser with CSP compatibility will only execute those scripts that are loaded from these whitelisted domains.

Please note that CSP makes XSS attack a lot harder but CSP does not make XSS attack impossible. CSP does not stop DOM-based XSS (also known as client-side XSS). To prevent DOM-based XSS, Javascript code should be carefully written to avoid introducing such vulnerabilities.

In Rails 5.2, a DSL was added for configuring Content Security Policy header.

Let's check the configuration.

We can define global policy for the project in an initializer.

1
2# config/initializers/content_security_policy.rb
3
4Rails.application.config.content_security_policy do |policy|
5policy.default_src :self, :https
6policy.font_src :self, :https, :data
7policy.img_src :self, :https, :data
8policy.object_src :none
9policy.script_src :self, :https
10policy.style_src :self, :https, :unsafe_inline
11policy.report_uri "/csp-violation-report-endpoint"
12end

We can override global policy within a controller as well.

1
2# Override policy inline
3
4class PostsController < ApplicationController
5content_security_policy do |policy|
6policy.upgrade_insecure_requests true
7end
8end
1
2# Using mixed static and dynamic values
3
4class PostsController < ApplicationController
5content_security_policy do |policy|
6policy.base_uri :self, -> { "https://#{current_user.domain}.example.com" }
7end
8end

Content Security Policy can be deployed in report-only mode as well.

Here is global setting in an initializer.

1
2# config/initializers/content_security_policy.rb
3
4Rails.application.config.content_security_policy_report_only = true

Here we are putting an override at controller level.

1class PostsController < ApplicationController
2content_security_policy_report_only only: :index
3end

Policy specified in content_security_policy_report_only header will not be enforced, but any violations will be reported to a provided URI. We can provide this violation report URI in report_uri option.

1
2# config/initializers/content_security_policy.rb
3
4Rails.application.config.content_security_policy do |policy|
5policy.report_uri "/csp-violation-report-endpoint"
6end

If both content_security_policy_report_only and content_security_policy headers are present in the same response then policy specified in content_security_policy header will be enforced while content_security_policy_report_only policy will generate reports but will not be enforced.

Stay up to date with our blogs. Sign up for our newsletter.

We write about Ruby on Rails, ReactJS, React Native, remote work,open source, engineering & design.