アプリ制作で個人情報の扱いには気をつけなければなりません。
特に、氏名や住所、電話番号など個人情報をデータベースにそのまま保存してしまうと、何らかのサーバー攻撃を受けた際に個人情報がそのまま漏洩してしまうリスクがあります。
そこで、万が一にも備えてデータベースの情報は暗号化しておく必要があります。
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暗号化を利用して個人情報をデータベースに保存した場合、個人情報は暗号化された状態でデータベースに格納されます。
そして、暗号化された個人情報をデータベースから取得する際は、アプリケーションがうまい具合に復号化して表示してくれます。
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 暗号化を実装する手順
それでは、さっそく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
これで暗号化の準備は整いました。
あとは、モデルにデータを追加してテストしてみましょう。
データベースの、指定したカラムの値が暗号化されていたら成功です。
データベースに暗号化して保存されたデータは、アプリケーション内でうまい具合に復号化してくれるので、以下のようにいつも通りにモデル.属性名
で呼び出すことができます。
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
カラムに保存される)
コメント