【Rails7】Active Record Encryption で特定のデータベース情報を暗号化する方法

アプリ制作で個人情報の扱いには気をつけなければなりません。

特に、氏名や住所、電話番号など個人情報をデータベースにそのまま保存してしまうと、何らかのサーバー攻撃を受けた際に個人情報がそのまま漏洩してしまうリスクがあります。

そこで、万が一にも備えてデータベースの情報は暗号化しておく必要があります。

Rails7では特定のデータベースの属性値を簡単に暗号化できる新機能(Active Record Encryption)が導入されたので、今回はその暗号化機能のセットアップ方法および使用方法について書いていきます。

目次

開発環境

  • Ruby 3.1.2
  • Ruby on Rails 7.0.3
  • Bootstrap 5.1.3
  • jsbundling-rails (1.0.3)
  • cssbundling-rails (1.1.1)
  • M1 Macbook Air 2020
  • mac OS Monterey (ver. 12.4)
  • ターミナル bash (Rosetta 2 使用

Active Record 暗号化(Active Record Encryption)とは?

Active Record暗号化(Active Record Encryption)は、Rails7から導入されたActive Recordの新機能です。

暗号化したいカラム(属性)を任意に指定することが可能で、データの暗号化や復号化(データベース間のやり取り)はバックグランドで自動でやってくれます。

そのため、アプリケーション内でデータを扱う際は暗号化・復号化のことを一切気にせず利用することができるのが大きなメリットです。

例えば、個人情報をそのままデータベースに保存した場合、データベースにアクセスすると以下のようにデータがそのまま表示されます。

暗号化なし

一方、Active Record暗号化を利用して個人情報をデータベースに保存した場合、個人情報は暗号化された状態でデータベースに格納されます。

Active Record 暗号化

そして、暗号化された個人情報をデータベースから取得する際は、アプリケーションがうまい具合に復号化して表示してくれます。

irb(main):001:0> person = Person.first
irb(main):002:0> person.age # => 34
irb(main):003:0> person.birthday # => Sat, 20 Aug 1988
irb(main):004:0> person.address # => "愛知県名古屋市中区栄1-2-3"

viewやコントローラーなど特にコードをいじる必要もなく、ただ暗号化したいモデルのカラム(属性)を指定するだけで背後でデータを自動で暗号化・復号化してくれるので便利ですね。

Active Record と暗号化 - Railsガ...
Active Record と暗号化 - Railsガイド Active Recordを用いてデータベースの情報を暗号化する方法について解説します。

Active Record 暗号化を実装する手順

それでは、さっそくActive Record暗号化を導入していきます。

暗号化キーを生成する

まずは、以下のコマンドを実行して暗号化キーを生成します。

$ rails db:encryption:init

以下のように、3種類のキー(32バイト長のランダムな文字列)が生成されます。

Add this entry to the credentials of the target environment: 
                                
active_record_encryption:       
  primary_key: ◯◯◯○◯◯◯○◯◯◯○◯◯◯○◯◯◯○◯◯◯○◯◯◯○◯◯◯○
  deterministic_key: △△△△△△△△△△△△△△△△△△△△△△△△△△△△
  key_derivation_salt: $ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

暗号化キーのセットアップ

続いて、暗号化キーをアプリケーションにセットアップします。

暗号化キーをそのままアプリケーションに設定するのはセキュリティ上よろしくないので、暗号化キーは環境変数として利用するようにします。

環境変数を利用するためには以下のgemが必要です。

gem "dotenv-rails"
$ bundle install

環境変数用のgemを導入したら、アプリフォルダ直下に.envファイルを新規作成し、先ほど生成した暗号化キーを追記します。(下記を参照)

PRIMARY_KEY = "◯◯◯○◯◯◯○◯◯◯○◯◯◯○◯◯◯○◯◯◯○◯◯◯○◯◯◯○"
DETERMINISTIC_KEY = "△△△△△△△△△△△△△△△△△△△△△△△△△△△△"
KEY_DERIVATION_SALT = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

この.envファイルですが、このままだと$ git pushした時にリモートリポジトリにアップされてしまうので、それを回避するために.gitignoreに以下を追記します。

/.env

.envファイルに暗号化キーを記述したら、config/application.rbでアプリケーションに暗号化キーを設定します。

module アプリ名
  class Application < Rails::Application

  ・・・

    # Active Record 暗号化キーの設定
    config.active_record.encryption.primary_key = ENV['PRIMARY_KEY']
    config.active_record.encryption.deterministic_key = ENV['DETERMINISTIC_KEY']
    config.active_record.encryption.key_derivation_salt = ENV['KEY_DERIVATION_SALT']
  end
end

これで、Active Record暗号化を利用できるようになります。

(railsサーバーを立ち上げている場合は再起動して設定を反映させます)

暗号化属性の宣言

続いては、暗号化したいカラム(属性)を宣言します。

暗号化したいカラムがあるモデルに以下のようにカラムを指定します。

class Person < ApplicationRecord
  encrypts :name
end

カラムを複数指定する場合は以下のようにカンマで区切って入力します。

class Person < ApplicationRecord
  encrypts :name, :age, :birthday, :address, ...
end

これで暗号化の準備は整いました。

あとは、モデルにデータを追加してテストしてみましょう。

データベースの、指定したカラムの値が暗号化されていたら成功です。

Active Record 暗号化

データベースに暗号化して保存されたデータは、アプリケーション内でうまい具合に復号化してくれるので、以下のようにいつも通りにモデル.属性名で呼び出すことができます。

irb(main):001:0> person = Person.first
irb(main):002:0> person.age # => 34
irb(main):003:0> person.birthday # => Sat, 20 Aug 1988
irb(main):004:0> person.address # => "愛知県名古屋市中区栄1-2-3"

便利ですね。

Eメールアドレス(一意性制約のある値)の暗号化におけるオプション指定方法

これまでは、一意性制約のないデータを暗号化する方法について述べましたが、

Eメールアドレスやアカウント名など一意性制約のある(大文字小文字を区別しない)データーを暗号化する場合は、encryptsに対してdeterministicオプションを指定する必要があります。

(暗号化属性を宣言するときにdowncase:オプションを指定することでコンテンツ暗号化の前に小文字に揃えておくことができます)

class Person
  encrypts :email, deterministic: true, downcase: true
end

ActiveRecord暗号化では、決定論的な(deterministic)暗号化非決定論的な(non-deterministic)暗号化の2タイプあり、デフォルトでは非決定論的暗号化が用いられます。非決定論的暗号化では、同じコンテンツを同じパスワードで暗号化しても、暗号化のたびに異なる暗号文が生成されるため、暗号解析の難易度を高めてデータベースへのクエリを不可能にすることでセキュリティを向上させています。ただし、一意性制約のあるデータを暗号化する場合は決定論的暗号化(determinsticオプションを指定)を用いる必要があります。詳しくはこちら

また、大文字小文字の区別を失わずに、クエリでのみ大文字小文字を区別しないようにしたい場合は、downcase:オプションの代わりにignore_case:オプションを指定します。

class Person
  encrypts :name, deterministic: true, ignore_case: true
end

ただし、このオプションを利用する場合は、大文字小文字の区別を維持したデータを保存するためのoriginal_<カラム名>というカラムを追加する必要があります。

(大文字小文字の区別を維持したデータはoriginal_nameカラムに保存される)

参考資料

Madogiwa Blog
Ruby on Rails: Active Record Encryptionを使って属性値を暗号化するメモ - Madogiwa Blog Ruby on Rails 7から導入されたActive Record Encryptionを使ってみたところ大分良さそうだったので使い方とかをメモしてきます🗒 Active Record Encryptionとは? Active R...
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

愛知の34歳。無職で暇になり始めたプログラミング(Ruby on Rails)の忘備録をまとめたブログです。最近は別にやりたいことができたのでプログラミングほぼやっていません。気が向いたらまた再開するかも。僕の日常はメインブログの方で更新しています。

コメント

コメントする

目次