This blog is part of our Rails 6 series. Rails 6.0 was recently released.

A lot of times, we ask user for sensitive data such as password, credit card number etc. We should not be able to see this information in logs. So, there must be a way in Rails to filter out these parameters from logs.

Rails provides a way of doing this. We can add parameters to Rails.application.config.filter_parameters.

There is one more way of doing this in Rails. We can also use https://api.rubyonrails.org/classes/ActionDispatch/Http/FilterParameters.html.

However there is still a security issue when we call inspect on an ActiveRecord object for logging purposes. In this case, Rails does not consider Rails.application.config.filter_parameters and displays the sensitive information.

Rails 6 fixes this. It considers Rails.application.config.filter_parameters while inspecting an object.

Rails 6 also provides an alternative way to filter columns on ActiveRecord level by adding filter_attributes on ActiveRecord::Base.

In Rails 6, filter_attributes on ActiveRecord::Base takes priority over Rails.application.config.filter_parameters.

Let’s checkout how it works.

Rails 6.0.0.rc1

Let’s create a user record and call inspect on it.

>> class User < ApplicationRecord
>>  validates :email, :password, presence: true
>> end

=> {:presence=>true}

>> User.create(email: 'john@bigbinary.com', password: 'john_wick_bigbinary')
BEGIN
  User Create (0.6ms)  INSERT INTO "users" ("email", "password", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["email", "john@bigbinary.com"], ["password", "john_wick_bigbinary"], ["created_at", "2019-05-17 21:34:34.504394"], ["updated_at", "2019-05-17 21:34:34.504394"]]
COMMIT

=> #<User id: 2, email: "john@bigbinary.com", password: [FILTERED], created_at: "2019-05-17 21:34:34", updated_at: "2019-05-17 21:34:34">

We can see that password is filtered as it is added to Rails.application.config.filter_parameters by default in config/initializers/filter_parameter_logging.rb.

Now let’s add just :email to User.filter_attributes

>> User.filter_attributes = [:email]

=> [:email]

>> User.first.inspect
SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]

=> "#<User id: 2, email: [FILTERED], password: \"john_wick_bigbinary\", created_at: \"2019-05-17 21:34:34\", updated_at: \"2019-05-17 21:34:34\">"

We can see here that User.filter_attributes took priority over Rails.application.config.filter_parameters and removed filtering from password and filtered just email.

Now, let’s add both :email and :password to User.filter_attributes.

>> User.filter_attributes = [:email, :password]

=> [:email, :password]

>> User.first.inspect

=> "#<User id: 2, email: [FILTERED], password: [FILTERED], created_at: \"2019-05-17 21:34:34\", updated_at: \"2019-05-17 21:34:34\">"

We can see that now both email and password are filtered out.

Here is the relevant pull request.