Follow Me Icons

 

Follow @KendrickColeman on TwitterConnect on LinkedInWatch My Videos on YouTubeFollow me on FacebookCheck Out My Projects on GitHubStay Up To Date with RSS

Search

BSA 728x90 Center Banner

Encrypting Data Using attr_encrypted With Rails

I'm making a new application that will be public facing but I don't want any clear text being stored on the server for any user at anytime. This way, there will be no compromising of data. In this case, username and password credentials. This isn't an application where a user will login with their creds, if that were the case I would have used Devise. Instead, I'm taking these username and password credentials and piping them in to the application to talk to an outside service.

 

The first part of obscurity was making the Rails model create new entries based on UUID instead of sequential numbers. That was pretty easy by following this tutorial How to start using UUID in ActiveRecord with PostgreSQL. The second part was implementing the attr_encrypted gem. attr_encrypted allows you to store data in encrypted format to your ActiveRecord database. In this case, i'm using Postgres. 

 

The README is a start but doesn't get you all the way there. So here is how it's done.

 

Start off by creating a new scaffold. You must specify encrypted_ before anything you want encrypted in the model

rails g scaffold Model encrypted_user:string encrypted_password:string host:string

 

 

Here is the migration file:

class CreateModels < ActiveRecord::Migration
  def change
    create_table :models do |t|
      t.string :encrypted_user
      t.string :encrypted_password
      t.string :host

      t.timestamps
    end
  end
end

 

perform rake:db migrate

rake db:migrate
== 20150111200010 CreateModels: migrating =====================================
-- create_table(:models)
   -> 0.0112s
== 20150111200010 CreateModels: migrated (0.0114s) ============================

 

Open up the model.rb file and add the attr_encrypted attributes for anything you are wanting to encrypt. attr_encrypted_options.merge! sets paramters for all attr_encrypted lines. encode is set to true on ActiveRecord by default, but I set it anyway. In this example, I'm using the Figaro gem to keep things even more secure because the 256-bit keys I'm using are stored as Environment Variables and will not be accessible in github.

class Model < ActiveRecord::Base
	attr_encrypted_options.merge!(:encode => true)
	attr_encrypted :user, :key => ENV["USERKEY"]
	attr_encrypted :password, :key => ENV["PASSWORDKEY"]
end

 

We need to change our controller next. At the very bottom of a default scaffolding is the modelname_params method. We need to remove encrypted_ from each of those

### BEFORE
def model_params
      params.require(:model).permit(:encrypted_user, :encrypted_password, :host)
 end


### AFTER
def model_params
      params.require(:model).permit(:user, :password, :host)
 end

 

 

Finally, Let's change our _form. The submitted text_field value now needs to match the params specified above:

<%= form_for(@model) do |f| %>
  <% if @model.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@model.errors.count, "error") %> prohibited this model from being saved:</h2>

      <ul>
      <% @model.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :encrypted_user %><br>
    <%= f.text_field :user %>
  </div>
  <div class="field">
    <%= f.label :encrypted_password %><br>
    <%= f.text_field :password %>
  </div>
  <div class="field">
    <%= f.label :host %><br>
    <%= f.text_field :host %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

 

Now we have additional methods available to us. If we do Model.username then we will see the unencrypted username. If we specify Model.encrypted_username then it will show the encrypted version. This can be verified by looking at the show page and adding in the additional methods.

<p id="notice"><%= notice %></p>

<p>
  <strong>Encrypted user:</strong>
  <%= @model.user %><br>
  <%= @model.encrypted_user %>
</p>

<p>
  <strong>Encrypted password:</strong>
  <%= @model.password %><br>
  <%= @model.encrypted_password %>
</p>

<p>
  <strong>Host:</strong>
  <%= @model.host %>
</p>

<%= link_to 'Edit', edit_model_path(@model) %> |
<%= link_to 'Back', models_path %>

 

And here is a resulting screenshot 

 

This can also be verified in the rails console if you bring up a record or create a new one:

2.1.2 :003 > @user = Model.new
 => #<Model id: nil, encrypted_user: nil, encrypted_password: nil, host: nil, created_at: nil, updated_at: nil>
2.1.2 :004 > @user.user = "kenny"
 => "kenny"
2.1.2 :005 > @user.save
   (0.4ms)  BEGIN
  SQL (2.1ms)  INSERT INTO "models" ("created_at", "encrypted_user", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["created_at", "2015-01-11 20:11:27.987417"], ["encrypted_user", "t+vBFbEvvy9hju1Crl10KQ==\n"], ["updated_at", "2015-01-11 20:11:27.987417"]]
   (1.6ms)  COMMIT
 => true
2.1.2 :006 > exit

 

Related Items