7

Active Record Encryption in Rails 7

 3 years ago
source link: https://blog.kiprosh.com/activerecord-encryption-in-rails-7/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
encryption Published on 16 September 2021 16 September 2021 • 4 min read

Active Record Encryption in Rails 7

If you're hosting your web server in a particular region, it might be necessary to comply with the GDPR norms of that region. Anonymizing and encrypting data becomes necessary in such situations. In this blog, we will discuss the attribute encryption that Rails 7 provides right out of the box. And we will also see the Deterministic & Non Deterministic approaches. (If you're using Rails version lesser than 7, check out our previous blog here on how to write a custom encryption framework.)

JPEG-image-E1C4FB16B212-1.jpeg

Apart from this, encryption also helps protect against data breach. Sensitive information like customer's email, phone or home address must be encrypted and filtered at the application level as it adds an additional layer of protection against unauthorized access to the database, application console or server logs.


Installing Rails 7

As of the time of writing this blog, Rails 7 is still in the alpha phase. You can install it by adding this to your Gemfile.

gem 'rails', github: 'rails/rails', branch: 'main'

Run bundle install to install the gem and verify the gem version using the rails -v command.

$ rails -v
Rails 7.0.0.alpha

Voila! You've successfully installed Rails 7.

Initializing Encryption keys

To get started with encryption, first, we'd need to initialize some keys that will be used by the encrypts API to encrypt and decrypt attributes.
Run bin/rails db:encryption:init to generate a random key set.

$ bin/rails db:encryption:init
Add this entry to the credentials of the target environment:

active_record_encryption:
  primary_key: EGY8WhulUOXixybod7ZWwMIL68R9o5kC
  deterministic_key: aPA5XyALhf75NNnMzaspW7akTfZp0lPY
  key_derivation_salt: xEY0dt6TZcAMg52K7O84wYzkjvbA62Hz

Add the generated key set to your RoR application's credentials file.

  • primary_key - Used to derive the root encryption key for non-deterministic encryption.
  • deterministic_key - Used to derive the root encryption key for deterministic encryption.
  • key_derivation_salt - Sequence of bits added to the root key to strengthen it further.

Declaration of Encrypted Attribute

To encrypt any attribute, we simply need to add a declaration encrypts at the model level.

class User
  encrypts :email
end

Deterministic & Non Deterministic approach

By default, Rails uses a non-deterministic (also known as probabilistic) approach to encrypt the plain text. Under the hood, it uses a random initialization vector to encrypt the plain text. Due to this, the same plain text will generate a different cipher each time it is encrypted making it harder for the attacker to find patterns in the encrypted data and eventually guessing the key.

But wait a minute. Querying non-deterministically encrypted data is impossible now.

User.create email: '[email protected]'
# => <User:0x00 id: 1, email: "[email protected]"...>

User.find_by email: '[email protected]'
# => nil

If you want to directly query an encrypted column attribute, you'd need to use the deterministic approach. For this, simply use the deterministic: true option during declaration.

class User
  encrypts :email, deterministic: true
end

User.create email: '[email protected]'
# => <User:0x00 id: 1, email: "[email protected]"...>

User.find_by email: '[email protected]'
# => <User:0x00 id: 1, email: "[email protected]"...>

Under the hood, rails will use a fixed initialization vector for encryption. As you might've already guessed, this is not very secure. Hence, it is recommended to use non-deterministic approach if querying the column is not required.

Encryption Key Management

Encryption Key Rotation

ActiveRecord Encryption allows support for key rotation by providing a list of keys to active_record.encryption.primary_key

active_record:
  encryption:
    primary_key:
      - a1cc4d7b9f420e40a337b9e68c5ecec6 # Used for decryption only
      - bc17e7b413fd4720716a7633027f8cc4 # Used for encryption & decryption

From the above list of primary keys, the last key will always be used for encryption and all listed keys will be used for decryption until one of them works.

Decryption can be made more performant by storing the reference id of the encryption key in the encrypted message itself.

config.active_record.encryption.store_key_references = true

Now, the decryption key can be accessed directly without having to try out every key to find out which one works. Neat!

Note: Key rotation is not supported for deterministic encryption as of yet.

Built-in Encryption Key Providers

ActiveRecord Encryption further lets you control the key management strategies by allowing you to choose between different key providers.

Rails 7 comes with two built-in key providers to choose from:

  • DerivedSecretKeyProvider (default) :
    Serves encryption & decryption keys derived from the provided passwords using PBKDF2.

  • EnvelopeEncryptionKeyProvider :
    The envelope encryption strategy uses a random secret to encrypt the plain text. The random secret is then encrypted using the encryption key and included in the encrypted message's headers. You can enable this by setting the following in your application.rb.

    config.active_record.encryption.key_provider = ActiveRecord::Encryption::EnvelopeEncryptionKeyProvider.new
    

ActiveRecord Encryption has tons of other configurations which are worth checking out. You can refer to the Rails edge guides to find out more about them. Hope you find this blog helpful. Thank you for reading!

References


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK