Rails Content Security Policy: Optimize Your Security

Welcome to the world of web security, where staying updated on the latest safety measures is crucial to keep your applications secure! One essential tool for protecting your Rails applications is the Rails Content Security Policy (CSP). With security threats growing more complex each year, it’s vital to implement robust solutions like CSP.

In this friendly guide, we’ll dive into the Rails Content Security Policy, helping you understand what it is, why it matters, and how to enable it. We’ll also walk you through some common errors you may face and provide tips for addressing them. So let’s jump in and explore the Rails CSP together to make your web applications more secure than ever!

If you happen to have no experience developing in Ruby on Rails or you’re just testing the waters, we highly recommend you take some time to explore this article and get acquainted with it. We’ll address some features that might not be immediately clear unless you have some background in Rails.

Content Security Policy

Content Security Policy is a collection of policies or directions that your browser enforces on web pages when requested. While loading a page, the browser has to request and render content and code—a lot of it. This process is standard and usually harmless as pretty much all modern websites are in nature complex and composed of lots of lines of HTML, CSS, JavaScript, and other resources like images and files that the code references. The referenced code could be from the same origin (requested domain) or another origin; browsers don’t distinguish. The browsers then have to process and execute these resources without any malicious code or access data not belonging to the website in question.

To ensure security, the server provides a CSP through the response header to guarantee that the browser executes only valid resources. This security layer helps mitigate attackers from taking advantage of vulnerabilities like cross-site scripting (XSS) and injection attacks by providing an allowlist of trusted resources.

Let’s see what a Content Security Policy header would look like:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self'; frame-src 'self';

Notice that each section in the header is relevant to a specific kind of source. 

Additionally, the default ‘self’ directive states that only resources from the same origin must be executed. You can specify domains from which you want to retrieve resources by putting their URLs next to ‘self’. Additionally, you can allow all domains by setting ‘*’ (but don’t do this unless you absolutely have to).

How to Enable Rails Content Security Policy

Well then, now that we’re more familiar with Content Security Policy and know how it looks, let’s see it in our code.

To implement Rails Content Security Policy, you first have to check which version of Rails you’re running. Rails 5.2 added CSP support, so you’re already implementing CSP in your application if you’re running on 5.2 or above. If you’re on 5.2 or above, your policies settings lie in the application config file like below.

# config/initializers/content_security_policy.rb

Rails.application.config.content_security_policy do |policy|
  policy.default_src :self, :https
  policy.font_src :self, :https, :data
  policy.img_src :self, :https, :data
  policy.object_src :none
  policy.script_src :self, :https
  policy.style_src :self, :https, :unsafe_inline
  policy.report_uri "/csp-violation-report-endpoint"
end

If, however, you’re below 5.2, you can use the SecureHeaders gem to add CSP to legacy applications. Now you can proceed to your initializer file containing the CSP directives (usually called ‘csp.rb’) and add the code if it doesn’t already exist.

# config/initializers/csp.rb

SecureHeaders::Configuration.default do |config|
  config.csp = {
    default_src: %w(https: 'self'),
    font_src: %w('self' data: https:),
    img_src: %w('self' https: data:),
    object_src: %w('none'),
    script_src: %w(https:),
    style_src: %w('self' https: 'unsafe-inline')
  }
end

Now you can check that all response headers contain the CSP configuration mentioned above if they didn’t before. The browser will enforce any changes, most likely breaking your page and displaying many alerts.

Rails Content Security Policy
Photo by David Pupaza on Unsplash

Proper Content Security Policies require a decent number of changes and testing. So, for now, let’s address the immediate errors while still having a functional site, and that’s where the ‘Content-Security-Policy-Report-Only’ alternative will be helpful.

# config/initializers/content_security_policy.rb

Rails.application.config.content_security_policy_report_only = true

Using “report only,” makes the browser no longer enforce the directives but continue to display the corresponding violation alerts. This behavior is helpful for development environments where the platform’s security is not essential, but the developer needs to be aware of any violations to address them adequately.

Common CSP Errors

Seeing all these alerts in the browser developer console can be scary, but don’t worry. Addressing them is very simple once you understand what your site is demanding. The report will be your guide to improve the policy directive and make the necessary updates. 

Our first step should be to confirm that the resources the browser is reporting are, in fact, legitimate and necessary for the proper functioning of the application. For example, we can see that our application is requesting the following:

https://code.jquery.com/jquery-3.5.1.min.js
https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js
https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.31/moment-timezone-with-data.js
https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js
https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js
https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js
https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-brands-400.woff2
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-brands-400.woff
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-brands-400.ttf
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-regular-400.woff2
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-regular-400.woff
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-regular-400.ttf
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-solid-900.woff2
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-solid-900.woff
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-solid-900.ttf

All these are valid resources that come from trusted origins.

Once you have the list of resources at hand, you can add them to the allowlist of each respective source as follows:

# config/initializers/content_security_policy.rb

Rails.application.config.content_security_policy do |policy|
  policy.default_src :self, :https
  policy.font_src :self, %w(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-brands-400.woff2 https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-brands-400.woff https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-brands-400.ttf https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-regular-400.woff2 https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-regular-400.woff https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-regular-400.ttf https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-solid-900.woff2 https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-solid-900.woff https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/fa-solid-900.ttf)

  policy.img_src :self, :https, :data
  policy.object_src :none
  policy.script_src :self, %w(https://code.jquery.com/jquery-3.5.1.min.js https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.31/moment-timezone-with-data.js https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js)

  policy.style_src :self, %w(https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css)

  policy.report_uri "/csp-violation-report-endpoint"

end

By doing this, most of the alerts go away.

Furthermore, if you want to enable all resources from a specific domain, you can do so by specifying the domain in the directive.

# config/initializers/content_security_policy.rb

Rails.application.config.content_security_policy do |policy|
  policy.default_src :self, :https
  policy.font_src :self, %w(https://cdnjs.cloudflare.com)
  policy.img_src :self, :https, :data
  policy.object_src :none
  policy.script_src :self, %w(https://code.jquery.com https://cdnjs.cloudflare.com https://stackpath.bootstrapcdn.com https://cdn.jsdelivr.net)
  policy.style_src :self, %w(https://stackpath.bootstrapcdn.com https://cdnjs.cloudflare.com)
  policy.report_uri "/csp-violation-report-endpoint"
end

But what about the inline code in our HTML? Well, we have a few options to approach these violations.

  • Move all inline code and inline styles to a file. This way, you can ensure the security of your application and keep it consistent.
  • Move the code to a tag and get its hash key. This hash key is generated by hashing the code inside the tag with a SHA256 algorithm. Conveniently, this hash is calculated for you by the alert itself so that you can add it directly to the directive, telling the browser that the code in this tag is allowed.
  • Use a ‘nonce’ tag attribute and add it to the corresponding tag. This solution will essentially serve the same purpose but must be updated with each request with some server-side code.

Ensuring Content Security

The process of securing our applications can be a very complicated and long journey. It’s easy to end up lost in a rabbit hole of articles and forums. Nevertheless, we must address security issues and exploits as much as possible.

Rails is a manageable and friendly platform to build robust and flexible applications. It makes the work of securing against Content Security Policy exploits very straightforward. No need to tamper with complex configurations or scary settings.

If you want to learn more about securing your platform from threats, you can find check out this article and learn how to create an API security catalog. So if you wish to make sure your Rails application is secure or you want to learn how to implement similar solutions in other technologies, you can find all you need here.

This post was originally written for and published by StackHawk.com


Posted

in

by

Comments

6 responses to “Rails Content Security Policy: Optimize Your Security”

  1. […] documentation, offers a mature platform that requires rigorous security measures. One of the security concerns that Rails developers often face is cross-site request forgery, also known as CSRF or […]

  2. ruby development Avatar
    ruby development

    Hello, just wanted to say, I loved this article. It was helpful.
    Keep on posting!

    1. Juan Reyes Avatar

      Thank you for the kind words. Really appreciate it.

  3. enamtechsolutions.com Avatar
    enamtechsolutions.com

    We are a group of volunteers and starting a new scheme in our community.
    Your site offered us with valuable information to work on.
    You have done a formidable job and our entire community will be thankful to
    you.

    1. Juan Reyes Avatar

      Wonderful to hear! Best of luck.

  4. […] cover various aspects of security testing, vulnerability management, container security, SIEM, and web application security. While each tool has its benefits and drawbacks, organizations must choose the tools that best suit […]

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.