New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encrypt your data with MessageEncryptor #10

Open
JuanitoFatas opened this Issue Nov 17, 2015 · 0 comments

Comments

Projects
None yet
1 participant
@JuanitoFatas
Member

JuanitoFatas commented Nov 17, 2015

Rails has a built-in class MessageEncryptor, which uses OpenSSL::Cipher to perform encryption. Read How does MessageEncryptor works or the source code if you are interested in its inner workings.

If you have been working with Ruby for a while, you would probably be familiar with attr_accessor, attr_reader and attr_writer which provide you with getter and/or setter. These methods are mostly convenient, but if you are required to store sensitive information in the database (i.e. OAuth token), then you will need your own custom getter and setter to protect the sensitive data.

You can make use of the #encrypt_and_sign and #decrypt_and_verify methods available in Rails to encrypt and decrypt data in your custom getter and setter, and here's how you can do it:

def token=(value)
  encrypted_token = cryptor.encrypt_and_sign(value)
  self[:token] = encrypted_token
end

def token
  encrypted_token = self[:token]

  if encrypted_token.present?
    cryptor.decrypt_and_verify(encrypted_token)
  end
end

private

  def cryptor
    ActiveSupport::MessageEncryptor.new(Rails.application.secrets.secret_key_base)
  end

Feeling paranoid? You can also pass in additional cipher:

ActiveSupport::MessageEncryptor.new(
  Rails.application.secrets.secret_key_base,
  cipher: "aes-256-ecb"
)

Pro-tip: You can get a list of available ciphers with $ openssl list-cipher-commands.

Testing it is also very simple (with RSpec):

describe "#token=" do
  it "saves encrypted token in database" do
    user = build(:user)
    user.token = "oauth token"

    user.save

    expect(user["token"]).not_to eq("oauth token")
  end
end

describe "#token" do
  it "returns decrypted token upon retrieval" do
    user = build(:user)
    user.token = "oauth token"

    user.save

    expect(user.reload.token).to eq("oauth token")
  end
end

Note that I have used FactoryGirl to perform a build(:user).

Alternatively, if you need a lot more features for your encrypted fields, you can also check out attr_encrypted gem.

Remember to secure sensitive information you store in your database! ❤️

Thanks for reading!

@JuanitoFatas ✏️ Jolly Good Code

About Jolly Good Code

Jolly Good Code

We specialise in Agile practices and Ruby, and we love contributing to open source.
Speak to us about your next big idea, or check out our projects.

@JuanitoFatas JuanitoFatas added the Blog label Nov 17, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment