Active Recordはアプリケーションレベルの暗号化をサポートします。これは、暗号化する属性を宣言し、必要に応じて暗号化と復号をシームレスに行うしくみです。暗号化の層は、データベース層とアプリケーション層の間に置かれます。アプリケーションがアクセスするのは暗号化されていないデータですが、データベースには暗号化されたデータが保存されます。

1 データをアプリケーションレベルで暗号化する理由

Active Record暗号化は、アプリケーション内の機密情報を保護するために存在します。典型的な機密情報の例は、個人を識別可能な情報です。既にデータベースを暗号化していてもアプリケーションレベルで暗号化したくなる理由は何でしょうか?

機密性の高い属性を暗号化することでただちに得られる実用的なメリットの1つは、セキュリティ層が追加されることです。たとえば、攻撃者がデータベースやデータベースのスナップショット、アプリケーションログにアクセスできたとしても、暗号化された情報は読めません。また、暗号化することで、開発者がうっかりユーザーの機密情報をアプリケーションログに出力してしまうことを防止できます。

しかしもっと重要なのは、Active Record暗号化を用いることで、アプリケーション内にある機密情報の構成要素をコードレベルで定義できることです。Active Record暗号化を利用すれば、アプリケーション内のデータアクセスやデータを実際に消費するサービスを細かく制御できるようになります。暗号化されたデータを保護する監査機能付きのRailsコンソールや、コントローラのparamsを自動フィルタする組み込みシステムなども検討できます。

2 基本的な利用法

2.1 セットアップ

bin/rails db:encryption:initを実行して、ランダムなキーセットを生成します。

$ bin/rails db:encryption:init
Add this entry to the credentials of the target environment:

active_record_encryption:
  primary_key: EGY8WhulUOXixybod7ZWwMIL68R9o5kC
  deterministic_key: aPA5XyALhf75NNnMzaspW7akTfZp0lPY
  key_derivation_salt: xEY0dt6TZcAMg52K7O84wYzkjvbA62Hz

これらの値は、生成された値を既存のRails credentialsにコピーして貼り付けることで保存できます。また、環境変数など他のソースを用いてこれらの値を設定することも可能です。

config.active_record.encryption.primary_key = ENV["ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY"]
config.active_record.encryption.deterministic_key = ENV["ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY"]
config.active_record.encryption.key_derivation_salt = ENV["ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT"]

生成される値は32バイト長です。これらを自分で生成する場合は、最低でも主キー用に12バイト(これはAESの32バイトのキー導出に用いられます)、ソルト(salt)用に20バイトが必要です。

2.2 暗号化属性の宣言

暗号化可能な属性はモデルレベルで定義します。これらの属性は、同名のカラムを用いる通常のActive Record属性です。

class Article < ApplicationRecord
  encrypts :title
end

このライブラリは、属性をデータベースに保存する前に透過的に暗号化し、取得時に復号するようになります。

article = Article.create title: "すべて暗号化せよ!"
article.title # => "すべて暗号化せよ!"

しかし背後で実行されるSQLは以下のようになります。

INSERT INTO `articles` (`title`) VALUES ('{\"p\":\"n7J0/ol+a7DRMeaE\",\"h\":{\"iv\":\"DXZMDWUKfp3bg/Yu\",\"at\":\"X1/YjMHbHD4talgF9dt61A==\"}}')
2.2.1 重要: ストレージとカラムのサイズについて

暗号化では容量が余分に必要です。これは、Base64エンコーディングや暗号化済みペイロードと一緒に保存されるメタデータがあるからです。 組み込みのエンベロープ暗号化キープロバイダを使う場合、最悪の場合のオーバーヘッドは約255バイトが見込まれます。このオーバーヘッドは、サイズが大きくなれば無視できるほど小さくなります。それに加えて、ライブラリがデフォルトで圧縮を行うため、大きなペイロードの場合、非暗号化バージョンと比較して最大30%のストレージ削減が可能です。

ただし、文字列のカラムサイズについては重要な懸念事項があります。 最近のデータベースでは、カラムサイズはバイト数ではなく、アロケーション可能な文字数(number of characters)で決定されます。

たとえば、UTF-8では1文字あたり4バイトまで利用可能なので、UTF-8を利用しているデータベースのカラムは、バイト数*で見ると、そのサイズの4倍まで容量が増加する可能性があります。そして、暗号化済みペイロードはBase64としてシリアライズされたバイナリ文字列なので、通常のstringカラムに保存可能です。これらはASCIIバイトのシーケンスなので、暗号化済みカラムは平文カラムの4倍までサイズが増加する可能性があります。

すなわち、データベースに保存するバイト数が同じでも、カラムのサイズは4倍大きくなければならないことになります。

これは、実際には以下のようになります。

  • 欧米のアルファベット(主にASCII文字)で書かれた短い文章を暗号化する場合は、カラムサイズを定義する際に255バイトのオーバーヘッド追加分を考慮しておく必要があります。

  • キリル文字のような非西洋アルファベットで書かれた短いテキストを暗号化する場合、カラムサイズを4倍にしておく必要があります。

  • 長い文章を暗号化する場合、カラムサイズに関する懸念は無視できます。

以下に例を示します。

暗号化するコンテンツ 元のカラムサイズ 暗号化カラムの推奨サイズ ストレージのオーバーヘッド(最大)
メールアドレス string(255) string(510) 255 bytes
絵文字の短いシーケンス string(255) string(1020) 255 bytes
非西洋アルファベットのサマリーテキスト string(500) string(2000) 255 bytes
任意の巨大テキスト text text 無視可能

2.3 決定論的暗号化と非決定論的暗号化について

ActiveRecord暗号化では、デフォルトで非決定論的な(non-deterministic)暗号化を用います。ここで言う非決定論的とは、同じコンテンツを同じパスワードで暗号化しても、暗号化のたびに異なる暗号文が生成されるという意味です。非決定論的な暗号化手法によって、暗号解析の難易度を高めてデータベースへのクエリを不可能にすることで、セキュリティを向上させます。

deterministic:オプションを指定することで、初期化ベクトルを決定論的な手法で生成できるようになり、暗号化データへのクエリを効率よく行えるようになります。

class Author < ApplicationRecord
  encrypts :email, deterministic: true
end

Author.find_by_email("some@email.com") # You can query the model normally

データをクエリする必要が生じない限り、非決定論的な手法が推奨されます。

非決定論的モードのActive Recordでは、256ビットキーとランダムな初期化ベクトルを用いるAES-GCMが使われます。決定論的モードも同様にAES-GCMを用いますが、その初期化ベクトルは、キーと暗号化対象コンテンツのHMAC-SHA-256ダイジェストとして生成されます。

deterministic_keyを省略すると、決定論的暗号化を無効にできます。

3 機能

3.1 Action Text

Action Textの属性宣言にencrypted: trueを渡すことで、属性を暗号化できます。

class Message < ApplicationRecord
  has_rich_text :content, encrypted: true
end

Action Text属性に個別の暗号化オプションを渡すことについてはまだサポートされていません。グローバルな暗号化オプションに設定されている非決定的暗号化が用いられます。

3.2 フィクスチャ

config/environmentsのtest.rbに以下のオプションを追加すると、Railsのフィクスチャが自動的に暗号化されるようになります。

config.active_record.encryption.encrypt_fixtures = true

この機能を有効にすると、暗号化済み属性はモデルで定義されている暗号化設定に沿って暗号化されるようになります。

3.2.1 Action Textのフィクスチャ

Action Textのフィクスチャを暗号化するには、fixtures/action_text/encrypted_rich_texts.ymlに置く必要があります。

3.3 サポートされる型

active_record.encryptionは、暗号化の前に背後の型を用いて値をシリアライズしますが、カスタムのmessage_serializerを使わない場合は、型は文字列としてシリアライズ可能でなければなりませんserializedなどの構造化された型はそのまま利用可能です。

カスタム型をサポートする必要がある場合は、シリアライズ化属性の利用が推奨されます。シリアライズ化属性の宣言は、以下のように暗号化宣言より上の行に置いてください。

# 正しい
class Article < ApplicationRecord
  serialize :title, type: Title
  encrypts :title
end

# 誤り
class Article < ApplicationRecord
  encrypts :title
  serialize :title, type: Title
end

3.4 大文字小文字を区別しない場合

決定論的に暗号化されたデータへのクエリで大文字小文字を区別しないようにする必要が生じることがあります。この場合、大文字小文字を区別しないクエリをやりやすくするには2とおりの方法が考えられます。

1つは、以下のように暗号化属性を宣言するときにdowncase:オプションを指定することでコンテンツ暗号化の前に小文字に揃えておくことです。

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

downcase:オプションを指定する場合は、元の大文字小文字の区別が失われます。大文字小文字の区別を失わずに、クエリでのみ大文字小文字を区別しないようにしたいこともあるでしょう。そのような場合は:ignore_caseオプションを指定できます。このオプションを利用する場合は、大文字小文字の区別を維持したコンテンツを保存するためのoriginal_<カラム名>というカラムを追加する必要があります。

class Label
  encrypts :name, deterministic: true, ignore_case: true # 大文字小文字を維持したコンテンツは`original_name`カラムに保存される
end

3.5 暗号化されていないデータのサポート

暗号化されていないデータを移行しやすくするため、このライブラリにはconfig.active_record.encryption.support_unencrypted_dataオプションも用意されています。このオプションをtrueにすると以下のようになります。

  • 実際には暗号化されていない暗号化済み属性を読み出してもエラーをraiseしなくなる
  • 決定論的に暗号化された属性を含むクエリに「クリアテキスト」バージョンの属性も含まれるようになり、暗号化の有無にかかわらずコンテンツを検索できるようになる。これを有効にするにはconfig.active_record.encryption.extend_queries = trueを設定する必要があります。

このオプションは、非暗号化データと暗号化済みデータの共存が避けられないので、あくまで過渡期の利用が目的です。デフォルトでは上記2つのオプションはどちらもfalseに設定されます。そしてこの設定は、あらゆるアプリケーションで推奨される目標でもあります。

3.6 以前の暗号化スキームのサポート

属性の暗号化プロパティを変更すれば既存のデータが破損します。たとえば、決定論的な属性を非決定的に変える場合、単にモデル内の宣言を変更すると、暗号化手法が異なるため、既存の暗号文を読み取れなくなってしまいます。

このような状況をサポートするため、以前の暗号化スキームを以下の2つのシナリオで利用される形で宣言できます。

  • ActiveRecord暗号化は、暗号化済みデータを読み取るときに現在の暗号化スキームが効かない場合は、以前の暗号化スキームで読み取りを試みる。
  • 決定論的に暗号化されたデータへのクエリでは、以前の暗号化スキームを用いた暗号化テキストも追加して、複数の暗号化スキームで暗号化されたデータのクエリをシームレスに行えるようにする。これを有効にするには、config.active_record.encryption.extend_queries = trueを設定しておかなければなりません。

以前の暗号化スキームは、以下のいずれかの方法で設定可能です。

  • グローバルに設定
  • 属性ごとに設定
3.6.1 以前の暗号化スキームをグローバルに設定する

以前の暗号化スキームは、config/application.rbで以下のようにprevious設定を用いてプロパティのリストとして追加可能です。

config.active_record.encryption.previous = [ { key_provider: MyOldKeyProvider.new } ]
3.6.2 以前の暗号化スキームを属性ごとに設定する

属性を宣言するときに以下のように:previousで指定します。

class Article
  encrypts :title, deterministic: true, previous: { deterministic: false }
end
3.6.3 暗号化スキームと決定論的な属性

以前の暗号化スキームを追加する場合、以下のように非決定論的/決定論的によって違いが生じます。

  • 非決定論的暗号化: 新しい情報は、常に最新の(すなわち現在の)暗号化スキームによって暗号化される
  • 決定論的暗号化: 新しい情報は、常にデフォルトで最も古い暗号化スキームによって暗号化される

決定的暗号化をあえて利用する場合は、暗号文を変えたくないのが普通です。この振る舞いはdeterministic: { fixed: false }で変更可能です。これにより、新しいデータを暗号化するときに最新の暗号化スキームが用いられるようになります。

3.7 一意性制約

一意性制約は、決定論的に暗号化されたデータでしか利用できません。

3.7.1 一意性バリデーション

一意性バリデーションは、config.active_record.encryption.extend_queries = trueによって拡張クエリが有効になっている限り、通常どおりサポートされます。

class Person
  validates :email_address, uniqueness: true
  encrypts :email_address, deterministic: true, downcase: true
end

これは、暗号化済みデータと非暗号化データを組み合わせた場合や、以前の暗号化スキームを設定した場合にも利用できます。

大文字小文字を区別しないようにしたい場合は、encrypts宣言でdowncase:またはignore_case:を必ず指定すること。また、バリデーション内ではcase_sensitive:は機能しません。

3.7.2 一意インデックス

決定論的に暗号化されたカラムで一意インデックスをサポートするには、その暗号文が絶対に変更されないようにしておく必要があります。

決定論的な属性ではそのために、複数の暗号化スキームが設定されている場合はデフォルトでは常に最も古い暗号化スキームを利用するようになっています。そうでないと、属性の暗号化プロパティの変更を別の方法で防止しない限り、一意インデックスが効かなくなってしまいます。

class Person
  encrypts :email_address, deterministic: true
end

3.8 暗号化カラムをparamsでフィルタする

デフォルトでは、暗号化済みカラムはRailsのログで自動的にフィルタされますconfig/application.rbに以下を追加することで、この振る舞いを無効にできます。

config.active_record.encryption.add_to_filter_parameters = false

フィルタを有効にした状態で、特定のカラムをフィルタから除外したい場合は、config.active_record.encryption.excluded_from_filter_parametersに以下を追加します。

config.active_record.encryption.excluded_from_filter_parameters = [:catchphrase]

フィルタパラメータを生成するとき、Railsはモデル名をプレフィックスとして使います。たとえば、Person#nameの場合、フィルタパラメータはperson.nameになります。

3.9 エンコード

このライブラリは、非決定論的に暗号化された文字列値のエンコードを維持します。

エンコーディングは、暗号化済みペイロードとともに保存されるので、デフォルトでは強制的にUTF-8エンコーディングが使われます。すなわち、値が同じでもエンコードが異なれば暗号文も異なるものになります。これは、クエリや一意性制約を機能させるうえでは避けたいものなので、ライブラリが代わりに自動的に変換します。

決定論的暗号化でデフォルトのエンコードを指定するには、以下の設定を使います。

config.active_record.encryption.forced_encoding_for_deterministic_encryption = Encoding::US_ASCII

この振る舞いを無効にして常にエンコードを維持するには、以下の設定を使います。

config.active_record.encryption.forced_encoding_for_deterministic_encryption = nil

3.10 圧縮

このライブラリは、暗号化済みペイロードをデフォルトで圧縮します。これにより、ペイロードが大きい場合にストレージスペースを最大30%節約できます。暗号化する属性にcompress: falseを設定することで、圧縮を無効できます。

class Article < ApplicationRecord
  encrypts :content, compress: false
end

圧縮に使うアルゴリズムをカスタム設定することも可能です。デフォルトの圧縮プログラムはZlibです。#deflate(data)#inflate(data)に応答するクラスまたはモジュールを作成すれば、独自の圧縮プログラムを実装できます。

require "zstd-ruby"

module ZstdCompressor
  def self.deflate(data)
    Zstd.compress(data)
  end

  def self.inflate(data)
    Zstd.decompress(data)
  end
end

class User
  encrypts :name, compressor: ZstdCompressor
end

以下のように、圧縮プログラムをグローバルに設定することも可能です。

config.active_record.encryption.compressor = ZstdCompressor

4 キーの管理

キープロバイダは、キー管理戦略を実装します。キープロバイダはグローバルに設定することも、属性ごとに指定することも可能です。

4.1 組み込みのキープロバイダ

4.1.1 DerivedSecretKeyProvider

DerivedSecretKeyProviderは、指定のパスワードからPBKDF2を用いて導出されるキーを提供するキープロバイダです。

config.active_record.encryption.key_provider = ActiveRecord::Encryption::DerivedSecretKeyProvider.new(["some passwords", "to derive keys from. ", "These should be in", "credentials"])

active_record.encryptionはデフォルトで、active_record.encryption.primary_keyで定義されているキーを用いるDerivedSecretKeyProviderを設定します。

4.1.2 EnvelopeEncryptionKeyProvider

EnvelopeEncryptionKeyProviderは、シンプルなエンベロープ暗号化戦略を実装します。

  • データ暗号化操作のたびにランダムなキーを生成する
  • データ自身のほかにデータキーも保存し、active_record.encryption.primary_key credentialで定義されている主キーを用いて暗号化される

以下をconfig/application.rbに追加することで、Active Recordでこのキープロバイダを使うよう設定できます。

config.active_record.encryption.key_provider = ActiveRecord::Encryption::EnvelopeEncryptionKeyProvider.new

他の組み込みのキープロバイダと同様に、active_record.encryption.primary_keyに主キーのリストを渡すことでキーローテーションスキームを実装できます。

4.2 カスタムのキープロバイダ

より高度なキー管理スキームを利用したい場合は、イニシャライザで以下のようにカスタムのキープロバイダを設定できます。

ActiveRecord::Encryption.key_provider = MyKeyProvider.new

キープロバイダは以下のインターフェイスを実装しなければなりません。

class MyKeyProvider
  def encryption_key
  end

  def decryption_keys(encrypted_message)
  end
end

2つのメソッドは、いずれもActiveRecord::Encryption::Keyオブジェクトを返します。

  • encryption_key: コンテンツの暗号化に使われたキーを返す
  • decryption_keys: 指定のメッセージを復号するのに使う可能性のあるキーのリストを返す

1つのキーには、メッセージと一緒に暗号化なしで保存される任意のタグを含められます。ActiveRecord::Encryption::Message#headersを使って、復号時にこれらの値を調べられます。

4.3 キープロバイダを属性ごとに指定する

key_provider:オプションで、キープロバイダを属性ごとに設定できます。

class Article < ApplicationRecord
  encrypts :summary, key_provider: ArticleKeyProvider.new
end

4.4 キーを属性ごとに指定する

key:オプションで、指定のキーを属性ごとに設定できます。

class Article < ApplicationRecord
  encrypts :summary, key: "some secret key for article summaries"
end

Active Recordは、データの暗号化や復号に使うキーをこのキーで導出します。

4.5 キーのローテーション

active_record.encryptionでは、キーローテーションスキームの実装をサポートするキーのリストを利用できます。

  • 新しいコンテンツの暗号化には最下行のキーが用いられる
  • 復号では、成功するまですべてのキーを試行する
active_record_encryption:
  primary_key:
    - a1cc4d7b9f420e40a337b9e68c5ecec6 # 以前のキーは引き続き既存コンテンツを復号する
    - bc17e7b413fd4720716a7633027f8cc4 # 新しいコンテンツを暗号化するアクティブなキー
  key_derivation_salt: a3226b97b3b2f8372d1fc6d497a0c0d3

これにより、「新しいキーの追加」「コンテンツの再暗号化」「古いキーの削除」を行ってキーのリストを短く保てるようになります。

キーローテーションは、決定論的暗号化では現在サポートされていません。

Active Record暗号化は、キーローテーション処理の自動管理機能をまだ提供していません(実装は可能ですが未実装の状態です)。

4.6 キー参照の保存

以下のようにactive_record.encryption.store_key_referencesを設定することで、active_record.encryptionが暗号化済みメッセージそのものに暗号化キーへの参照を保存するようになります。

config.active_record.encryption.store_key_references = true

この設定を有効にすると、システムがキーのリストを探索せずにキーを直接見つけられるようになり、復号のパフォーマンスが向上します。その代わり、暗号化データのサイズがやや肥大化します。

5 API

5.1 基本的なAPI

Active Record暗号化は宣言的に利用することを念頭に置いていますが、より高度なシナリオで使えるAPIも提供しています。

5.1.1 暗号化と復号
article.encrypt # encrypt or re-encrypt all the encryptable attributes
article.decrypt # decrypt all the encryptable attributes
5.1.2 暗号文の読み出し
article.ciphertext_for(:title)
5.1.3 属性が暗号化されているかどうかのチェック
article.encrypted_attribute?(:title)

6 設定

6.1 設定オプション

Active Record暗号化のオプションは、config/application.rbで行うことも(ほとんどの場合このファイルに書きます)、config/environments/<環境名>.rbで特定の環境設定ファイルに設定することも可能です。

キーの保存場所には、Rails組み込みのcredentialサポートを用いることが推奨されます。設定プロパティを用いて手動で設定したい場合は、キーを誤ってコードと一緒にリポジトリにコミットしないようご注意ください(環境変数などを用いること)。

6.1.1 config.active_record.encryption.support_unencrypted_data

trueにすると、非暗号化データを通常通り読み出せるようになります。 falseにすると、非暗号化データを読み出したときにエラーになります。デフォルトはfalseです。

6.1.2 config.active_record.encryption.extend_queries

trueに設定すると、決定論的に暗号化された属性を参照するクエリが、必要に応じて追加の値を含むように変更されます。追加される値は暗号化されない(config.active_record.encryption.support_unencrypted_datatrueの場合)か、または以前の暗号化スキームで暗号化されます(previous:で指定された場合)。デフォルトはfalseです。

6.1.3 config.active_record.encryption.encrypt_fixtures

trueの場合、フィクスチャ内の暗号化可能な属性が読み込み時に自動的に暗号化されます。デフォルトはfalseです。

6.1.4 config.active_record.encryption.store_key_references

trueにすると、暗号化キーへの参照が暗号化済みメッセージのヘッダ内に保存され、キーが複数使われている場合の暗号化が高速になります。デフォルトはfalseです。

6.1.5 config.active_record.encryption.add_to_filter_parameters

trueにすると、暗号化された属性名が自動的にconfig.filter_parametersに追加され、ログに出力されなくなります。デフォルトはtrueです。

6.1.6 config.active_record.encryption.excluded_from_filter_parameters

フィルタから除外するparamsのリストを設定します(add_to_filter_parameterstrueの場合)。デフォルトは[]です。

6.1.7 config.active_record.encryption.validate_column_size

カラムのサイズに応じたバリデーションを追加します。巨大な値を圧縮率の高いペイロードを用いて保存しないために推奨されている設定です。デフォルトはtrueです。

6.1.8 config.active_record.encryption.primary_key

rootデータ暗号化キーの導出に用いるキーまたはキーのリストを設定します。キーの利用法はキープロバイダの設定によって異なります。active_record_encryption.primary_key credentialで設定するのが望ましい方法です。

6.1.9 config.active_record.encryption.deterministic_key

決定論的暗号化で用いるキーまたはキーのリストを設定します。active_record_encryption.deterministic_key credentialで設定するのが望ましい方法です。

6.1.10 config.active_record.encryption.key_derivation_salt

キー導出時に用いるソルト(salt)を設定します。active_record_encryption.key_derivation_salt credentialで設定するのが望ましい方法です。

6.1.11 config.active_record.encryption.forced_encoding_for_deterministic_encryption

決定論的に暗号化された属性のデフォルトエンコーディングを設定します。このオプションをnilにするとエンコードの強制を無効化できます。デフォルトはEncoding::UTF_8です。

6.1.12 config.active_record.encryption.hash_digest_class

鍵の導出に使うダイジェストアルゴリズムです。デフォルトはOpenSSL::Digest::SHA256です。

6.1.13 config.active_record.encryption.support_sha1_for_non_deterministic_encryption

ダイジェストクラスSHA1で非決定的に暗号化されたデータの復号をサポートします。デフォルトはfalseで、config.active_record.encryption.hash_digest_classで設定されたダイジェストアルゴリズムのみをサポートします。

6.1.14 config.active_record.encryption.compressor

暗号化されたペイロードを圧縮するコンプレッサーライブラリを指定します。このライブラリは、deflateおよびinflateに応答する必要があります。デフォルトはZlibです。コンプレッサーについて詳しくは、圧縮セクションを参照してください。

6.2 暗号化コンテキスト

暗号化コンテキストとは、ある時点に使われる暗号化コンポーネントを定義するものです。デフォルトではグローバルな設定に基づいた暗号化コンテキストが使われますが、特定の属性で用いるカスタムコンテキストや、コードの特定のブロックを実行するときのカスタムコンテキストを定義可能です。

暗号化コンテキストの設定メカニズムは柔軟ですが高度です。ほとんどのユーザーは気にする必要はないはずです。

暗号化コンテキストに登場する主なコンポーネントは以下のとおりです。

  • encryptor: データの暗号化や復号に用いる内部APIを公開します。暗号化メッセージの作成とシリアライズのためにkey_providerとやりとりします。暗号化や復号そのものはcypherで行われ、シリアライズはmessage_serializerで行われます。
  • cipher: 暗号化アルゴリズムそのもの(AES 256 GCM)
  • key_provider: 暗号化と復号のキーを提供する
  • message_serializer: 暗号化されたペイロードをシリアライズおよびデシリアライズする(Message

独自のmessage_serializerを構築する場合は、任意のオブジェクトをデシリアライズすることのない安全なメカニズムを採用することが重要です。一般にサポートされているシナリオは、既存の非暗号化データを暗号化するときです。任意のオブジェクトがデシリアライズ可能だと、攻撃者がこれを利用して、暗号化が行われる前に改ざんしたペイロードを入力してリモートコード実行(RCE)を実行する可能性があります。つまり、独自のシリアライザではMarshalYAML.loadYAML.safe_loadにすること)、JSON.loadJSON.parseにすること)の利用を避けるべきです。

6.2.1 グローバルな暗号化コンテキスト

グローバルな暗号化コンテキストはデフォルトで利用されます。他の設定プロパティと同様、config/application.rbや環境ごとの設定ファイルで以下のように設定可能です。

config.active_record.encryption.key_provider = ActiveRecord::Encryption::EnvelopeEncryptionKeyProvider.new
config.active_record.encryption.encryptor = MyEncryptor.new
6.2.2 属性ごとの暗号化コンテキスト

以下のように属性の宣言で暗号化コンテキストを渡すことで、暗号化コンテキストを上書きできます。

class Attribute
  encrypts :title, encryptor: MyAttributeEncryptor.new
end
6.2.3 特定のコードブロックを実行中の暗号化コンテキスト

ActiveRecord::Encryption.with_encryption_contextを使うと、指定のコードブロックで暗号化コンテキストを設定できます。

ActiveRecord::Encryption.with_encryption_context(encryptor: ActiveRecord::Encryption::NullEncryptor.new) do
  # ...
end
6.2.4 Rails組み込みの暗号化コンテキスト
6.2.4.1 暗号化を無効にする

以下を用いると、暗号化を無効にしてコードを実行できます。

ActiveRecord::Encryption.without_encryption do
  #  ...
end

この場合、暗号化テキストを読み出すと暗号文のまま返され、saveしたコンテンツは暗号化なしで保存されることになります。

6.2.4.2 暗号化済みデータを保護する

以下を用いると、暗号化を無効にすると同時に、暗号化済みコンテンツが上書きされないようにコードを実行できます。

ActiveRecord::Encryption.protecting_encrypted_data do
  #  ...
end

これは、暗号化データを保護しつつ、任意のコードを実行したい場合に便利です(Railsコンソールなど)。

フィードバックについて

Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。

原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨

本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。

Railsガイド運営チーム (@RailsGuidesJP)

支援・協賛

Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。

  1. Star
  2. このエントリーをはてなブックマークに追加