You could use a before_save
hook to encrypt the sensitive attributes in the hash prior to being stored in the db and an after_initialize
hook to decrypt when the record is instantiated.
Something like the following should work:
class MyModel < ActiveRecord::Base
after_initialize :decrypt_sensitive
before_save :encrypt_sensitive
protected:
def encrypt_sensitive
props['some_attr'] = encrypt_and_mac(props['some_attr'])
props['another_attr'] = encrypt_and_mac(props['another_attr'])
end
def decrypt_sensitive
props['some_attr'] = decrypt_and_verify(props['some_attr'])
props['another_attr'] = decrypt_and_verify(props['another_attr'])
end
end
There will be some performance considerations with the after_initialize
so you may wish to consider using a custom accessor instead to perform the decryption lazily.
While I am all for layered security, you will not buy a lot of security without additional controls for both the platform and the key management. I specifically avoided details of cipher and encryption mode, key lengths, key management etc. You will need to be informed based on your own and/or your clients risk assessment (see the ISO 27000 series for information security risk management). Technically speaking, you may wish to consider AES with message authentication such as CCM or OCB3 so that you can detect if data at rest has been tampered with but you will still need to be careful how you use those modes too.
It is often the case that encryption is a mis-used tool that only serves to provide a false sense of security within an inherently insecure operational environment.