EncryptedAttributes
This gem provides a dead-simple encryption of string / text attributes of ActiveRecord and Mongoid models. Encryptor internally uses ActiveSupport::MessageEncryptor and therefore it uses 'aes-256-cbc' cipher by default. Currently there is no way to pass custom options to the encryptor. Gem does NOT require column with different name. It works just fine without it, but works only with columns of type string
or text
. From user perspective encryption is completely transparent - they use decrypted values all the time, but encrypted values are stored in database.
ORM Support
Integration with ActiveRecord and Mongoid has been tested. Other frameworks should work as expected if they provide #read_attribute
and #write_attribute
methods. They are supposed to work in similar way as in ActiveRecord.
Recommendations
Provided functionality is sufficient for storing oauth tokens and secrets that are not to be searched for. If you are looking for something more sophisticated, then check out my recommendations below.
attr_encrypted extends Object
, so it works with any Ruby class, but requires an encrypted attribute to have a different name than the regular one.
CryptKepper is a perfect solution if you need to search through encrypted fields, but supports ActiveRecord only.
symmetric-encryption is based on RSA-encrypted keys and supports ActiveRecord, MongoMapper and Mongoid. It provides type coercion and can be used to secure configuration files as well. PCI compliant.
Installation
Add this line to your application's Gemfile:
gem 'encrypt_attributes'
And then execute:
$ bundle
Or install it yourself as:
$ gem install encrypt_attributes
Usage
Provide a secret for Encryptor
. Create a model with fields of type string
or text
, include EncryptAttributes::Model
and call encrypt_attrs(*attrs)
.
Secret
If you are using Rails, secret by default will be set to Rails.application.secrets.secret_key_base
. If you want to use a different secret, create an initializer:
# config/initializers/encrypted_attributes.rb
EncryptAttributes::Encryptor.secret = "<super-secure-key>"
If you do not use Rails, set the secret before any encryption is done, otherwise an error will be thrown.
Models
- ActiveRecord
# db/migrate/create_authentications.rb
class CreateAuthentication < ActiveRecord::Migration
def change
create_table :authentications, force: true do |t|
t.string :token
t.string :secret
end
end
end
# app/models/authentication.rb
class Authentication < ActiveRecord::Base
include EncryptAttributes::Model
encrypt_attrs :token, :secret
end
- Mongoid
# app/models/authentication.rb
class Authentication
include Mongoid::Document
# it is important to include Mongoid::Document before
include EncryptAttributes::Model
field :token, type: String
field :secret, type: String
encrypt_attrs :token, :secret
end
Custom accessors
If you want to define custom accessors for encrypted attributes, create methods you need to override and call super
to execute encryption / decryption. It will work the same way with all supported ORMs.
# app/models/authentication.rb
class Authentication < ActiveRecord::Base
include EncryptAttributes::Model
encrypt_attrs :token, :secret
def secret
super.tap do |decrypted|
# do whatever you want here
end
end
def secret=(new_secret)
super
# do whatever you want here
end
end
Gotchas
Beware that each time encryption is done it returns a different value for the same input argument. Check out the consequences on the example below.
user = User.create(secret: "secret")
user.secret = "secret" # the same value
user.secret_changed? # returns true
ORMs will think that the secret has changed, because after setting a value, it gets encoded and a new value is stored in attributes
.
Running tests
Before running entire suite, you have to start Mongo DB, create and migrate database for ActiveRecord. Read more about Mongo installation. To prepare database:
bundle exec rake db:create
bundle exec rake db:migrate RACK_ENV=test
To run tests:
bundle exec rspec
Contributing
- Fork it ( https://github.com/aenain/encrypted_attributes/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request