Category ROR

In our last article about Rails 7 Alpha Releases, we briefly discussed Rails 7 adding encrypted attributes to Active Record models.

As a known fact, Active Record supports application-level encryption in which data encryption and decryption are performed at the end application. It works by declaring the attributes that should be encrypted and decrypting them as needed. The encryption layer sits between the database and the application. This is great for users who have ever had to encrypt data before storing it in the database.

So how is Rails 7 making encryption different for developers?

For starters, at-work encryption is now one of the instant benefits for Rubyists in addition to the traditional at-rest and in-transit coverage. With at-work encryption, the main database also deals with encrypted data while it’s working. It encrypts sensitive attributes thereby adding an extra layer of security. 

At-rest encryption encrypts the data while it’s stored but not in use. In-transit encryption only protects data in transit by creating an encrypted channel between a network or two computers for them to communicate over. 

These encryption methods can protect your data against physical threats, but become ineffective against compromised accounts or privilege misuse, making application-level encryption a far superior choice.

Encrypted Attributes to Active Record

Rails 7 uses Active Record for Encryption and Active Record by default uses a non-deterministic approach. By adding encryption to attributes at the model level, the library will transparently encrypt these attributes before saving them into the database and will decrypt them when retrieving their values. 

So by default, it will encrypt all data using the AES-GCM cipher with a non-deterministic approach. Meaning that the same text will be encrypted twice which results in different ciphertexts. Being natively supported in Ruby, AES-GCM is a good option for symmetric encryption. 

While this is great from a security point of view i.e. making crypto-analysis of encrypted content difficult, it makes querying the results quite challenging. 

You can still configure it to use a deterministic approach instead as per your project requirement. But keep in mind that reconfiguration to deterministic will lower security as it will have the same value for an encrypted attribute in the database.

Another issue when querying data that has been encrypted deterministically is when you attempt to combine encrypted and unencrypted data or data that is encrypted with different schemes. This has been resolved by extending Active Record to modify queries automatically. Check out this Rails pull for full details. 

Rails 7 uses EncryptableRecord concern to perform encryption and decryption when saving and retrieving values from the database, which makes ActiveRecord::Base records encryptable. It defines .encrypts and the record-level API.

Gem Dependency

Prior to this release, third-party gems like lockbox and attr_encrypted had to be installed to add encryption on attributes of Active Record models. The use of such third-party gems is bound to add an additional dependency for critical encryption functionality. Not to mention that adding gems bloat your codebase because of the extra lines of code. 

By adding encryption on attributes to ActiveRecord models, although the gem dependency is not completely eliminated, it is reduced to quite an extent.

5 Ruby on Rails Encryption Tools

If you’re someone who is in the habit of using gems for the purpose of securing your Rails application, feel free to check out the following list of download-worthy encryption tools.

  1. attr_encrypted

It generates attr_accessors that transparently encrypt and decrypt attributes and works with any class.

  1. rbnacl

Ruby binding for libsodium. 

  1. lockbox

Modern encryption for Ruby and Rails.

  1. crypt_keeper

Provides transparent encryption for Active Record.

  1. strongbox

Strongbox provides Public Key Encryption for ActiveRecord.

Encryption Setup in Rails 7

Rails 7 requires a pretty basic setup for encryption that entails adding some keys to our Rails credential file. Use the following command to generate the key set:

                   $ bin/rails db:encryption:init

This sets the key_derivation_salt, primary_key, and deterministic_key variables in our environment file.

Then, we specify the attributes to be encrypted in our model:

class User < ApplicationRecord
  encrypts: uuid

As simple as that, the product_id is successfully encrypted for the Product model before saving it to the database, and upon retrieving we can decrypt it.

As mentioned earlier, Rails 7 uses a non-deterministic approach that makes querying impossible, we use a deterministic approach to resolve this. In our model, we can specify deterministic as true along with the attribute to encrypted.

class User < ApplicationRecord
  encrypts: uuid ,deterministic: true

User.find_by(uuid: “1234”)

Built-in Encryption Key Providers

Rails 7 offers two built-in encryption-key providers:

  1. DerivedSecretKeyProvider (default)

A key provider that serves keys derived from the provided passwords using PBKDF2.

By default, active_record.encryption configures a DerivedSecretKeyProvider with the keys defined in active_record.encryption.primary_key

  1. EnvelopeEncryptionKeyProvider

Implementing the envelope encryption strategy, it uses a random secret to encrypt the plain text, which is further encrypted using the encryption key and included in the encrypted message's headers.

Active Record Encryption comes with loads of new configurations worth exploring. Here’s the full guide on how you can use encrypted attributes.

This article is written by Team RubyConf Pakistan in collaboration with Muhammad Hamza. Hamza is a Software Engineer at Sendoso. A graduate from FAST Lahore, he focuses as a professional is to keep learning new stuff and to hone his technical skills and expertise along with designing creative software and products.