The task at hand was to ensure that certain columns in the database are encrypted in case the database data is stolen. I have a feeling that a lot can be improved here (naming, DSL, encapsulations) while keeping the functionality as simple as it is. Let me know what you think, I'd appreciate any suggestions and ideas!
application_record.rb
class ApplicationRecord < ActiveRecord::Base
extend Encryptable
#...
end
encryptable.rb
module Encryptable
def encrypt_columns(*columns)
columns.each do |column|
if self.column_names.include?(column.to_s)
define_method "#{column}=" do |value|
self[column] = self.class.crypt.encrypt_and_sign(value)
end
define_method "#{column}" do
self.class.crypt.decrypt_and_verify(self[column])
end
end
end
end
def crypt
salt = '"\xCA)P\x9Dbc\xF7\x85B\xF3v}*p\xA6~\xBAR\xC1K\xE3\x88\xB8\x18\xF7\xD1\xB6e0\x98\xEF \xB9%\xB3\x12\x9C\xFE,\x89\xF4\xDE\xED!:7\xAE<q\xB1.<~\xA3m\e\x8C\t\xCF&/3\xCE\xAE"'
key = ActiveSupport::KeyGenerator.new('password').generate_key(salt)
@crypt ||= ActiveSupport::MessageEncryptor.new(key)
end
end
user.rb
class User < ApplicationRecord
encrypt_columns :email, :social_security_number
end
-
6\$\begingroup\$ Step 1: Don't hard-code your salt and password... \$\endgroup\$Flambino– Flambino2016年08月31日 15:44:41 +00:00Commented Aug 31, 2016 at 15:44
2 Answers 2
Some notes:
The recommended way to overwrite accessors is to use
super
.As @Flambino says, it's better not to hardcode secrets directly in the code. It can be a file not committed to the repository.
I'd write the
crypt
method this way:def crypt @crypt ||= begin key = ActiveSupport::KeyGenerator.new('password').generate_key('salt') ActiveSupport::MessageEncryptor.new(key) end end
There is already a gem for encrypting data at rest. Does this work for you? https://github.com/attr-encrypted/attr_encrypted
Explore related questions
See similar questions with these tags.