今回はRails7で導入されたデータベースの情報を暗号化する機能「ActiveRecord Encryption」を触ってみたので、その機能について簡単に紹介したいと思います。
これまでデータベースの情報を暗号化したい場合は、lockboxやbcrypt-rubyといった外部gemの使用が一般的でしたが、Rails7からはデフォルトでその機能が使えるようになりました。

ActiveRecord Encryptionとは
ActiveRecord Encryptionとは、アプリケーションレベルでの暗号化を提供する機能になります。この機能はRails7で導入されました。
特徴として、ActiveRecord Encryptionで暗号化されたデータはデータベースに置かれると暗号化されたままですが、ActiveRecordオブジェクトに読み込まれると自動的に復号化されるようになります。
コードを変える必要なくデータの暗号化と復号化をよしなに行なってくれるため、非常に便利な機能であると言えますね。
ActiveRecord Encryptionの使用方法
セットアップ
まずは以下のコマンドで暗号化に必要なキーを生成します。
% rails db:encryption:init
Add this entry to the credentials of the target environment:
active_record_encryption:
primary_key: vaebG7eRV9aPbQYP2HOUUVF1sO5OhTsJ
deterministic_key: MvwFKH0O5apPxAWR9IEBhl8JU0dp825N
key_derivation_salt: maHdkv5C8s2og7RgoUPebaQCjy4cGAIb
生成されたキーをcredentialsに定義します。
# VSCodeで開く場合
% EDITOR='code --wait' rails credentials:edit --environment development
# vimエディタで開く場合
% EDITOR=vi bin/rails credentials:edit --environment development
# development.yml.enc
active_record_encryption:
primary_key: vaebG7eRV9aPbQYP2HOUUVF1sO5OhTsJ
deterministic_key: MvwFKH0O5apPxAWR9IEBhl8JU0dp825N
key_derivation_salt: maHdkv5C8s2og7RgoUPebaQCjy4cGAIb

暗号化する属性の指定
暗号化したい属性(カラム)をモデルに定義します。
ユーザーの本名(real_name
)を暗号化したい場合は以下のような記述になります。
class User < ApplicationRecord
encrypts :real_name
end
ActiveRecord Encryptionは属性をデータベースに保存する前に透過的に暗号化し、取得時に復号化するようになります。
% rails c
> user = User.create(real_name: "田中太郎")
> user.real_name # => "田中太郎"
発行されるSQLを確認すると以下のようになっています。
INSERT INTO `users`(
`real_name`
)
VALUES(
'{\"p\":\"QDZh0FRTC68jZlVE\",\"h\":{\"iv\":\"GOLWCv0JZCXbIC9k\",\"at\":\"SQVZctAoyQDz7Bg3l1A9fw==\"}}'
)
期待通り、データベースに保存する際は暗号化され、ActiveRecordオブジェクトに読み込まれる際は復号化されていますね。
暗号化する属性の指定(複数)
暗号化する属性を複数指定したい場合は、以下のように繋げて記述することができます。
class User < ApplicationRecord
encrypts :name, :real_name, :age, :email
end
一意性制約のある属性の暗号化
一意性制約のある属性(重複を許容しない属性)を暗号化したい場合は、deterministic:
オプションを指定する必要があります。
class User < ApplicationRecord
encrypts :email, deterministic: true
end
ActiveRecord暗号化では、デフォルトで非決定論的な(non-deterministic)暗号化を用います。ここで言う非決定論的とは、同じコンテンツを同じパスワードで暗号化しても、暗号化のたびに異なる暗号文が生成されるという意味です。非決定論的な暗号化手法によって、暗号解析の難易度を高めてデータベースへのクエリを不可能にすることで、セキュリティを向上させます。
deterministic:
オプションを指定することで、初期化ベクトルを決定論的な手法で生成できるようになり、暗号化データへのクエリを効率よく行えるようになります。
また一意性制約でも大文字小文字を区別しない場合は、 downcase:
またはignore_case:
を必ず指定しなければなりません。
# 大文字小文字を区別しない
class User < ApplicationRecord
encrypts :email, deterministic: true, downcase: true
end
downcase:
オプションを指定する場合は、元の大文字小文字の区別が失われます。大文字小文字の区別を失わずに、クエリでのみ大文字小文字を区別しないようにしたいこともあるでしょう。そのような場合は:ignore_case
オプションを指定できます。このオプションを利用する場合は、大文字小文字の区別を維持したコンテンツを保存するためのoriginal_<カラム名>
というカラムを追加する必要があります。
class User
# 大文字小文字を維持したコンテンツは`original_email`カラムに保存される
encrypts :email, deterministic: true, ignore_case: true
end
参考: 大文字小文字を区別しない場合
まとめ
- ActiveRecord Encryptionとは、Rails7で導入されたアプリケーションレベルでの暗号化を提供する機能
- ActiveRecord Encryptionで暗号化されたデータは、データベースに置かれると暗号化されたままであるが、ActiveRecordオブジェクトに読み込まれると復号化されるという特徴を持つ
- 一意性制約のある属性(重複を許容しない属性)を暗号化したい場合は、
deterministic
オプションを指定する必要がある - 大文字小文字を区別しない場合は、
downcase:
またはignore_case:
を必ず指定しなければならない :ignore_case
オプションを指定した場合は、大文字小文字の区別を維持したコンテンツを保存するためのoriginal_<カラム名>
というカラムを追加する必要がある
参考
今回はRails7で導入されたデータベースの情報を暗号化する機能「ActiveRecord Encryption」について解説しました。暗号化と復号化をよしなに切り替えてくれるので、とても使いやすい機能だと個人的に感じました。