Rails

【Rails7】ActiveRecord Encryptionを用いてデータベースの情報を暗号化する方法メモ

Rails

 

今回はRails7で導入されたデータベースの情報を暗号化する機能「ActiveRecord Encryption」を触ってみたので、その機能について簡単に紹介したいと思います。

これまでデータベースの情報を暗号化したい場合は、lockboxbcrypt-rubyといった外部gemの使用が一般的でしたが、Rails7からはデフォルトでその機能が使えるようになりました。

Rails
【Rails】秘匿情報を暗号化し、管理することができるGem「lockbox」の使い方について簡単にまとめてみる秘匿情報を暗号化した状態で管理することができるGem「lockbox」の使い方について簡単に解説しています。秘匿情報を扱う際の選択肢の1つになれば幸いです。...

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
今回は開発環境で動作確認を行うため、development.yml.encのみ生成しています。
Rails
【Rails】秘匿情報を環境毎に管理することができるMulti Environment Credentialsについて初心者向けにまとめてみた今回は秘匿情報を環境毎に管理することができるMulti Environment Credentialsについて簡単にまとめたので紹介しています。付与されている権限によって閲覧できる情報を管理することができるため、権限の異なる複数人で開発する際にはもってこいの機能になります。...

暗号化する属性の指定

暗号化したい属性(カラム)をモデルに定義します。

ユーザーの本名(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」について解説しました。暗号化と復号化をよしなに切り替えてくれるので、とても使いやすい機能だと個人的に感じました。