🔑

可逆暗号化をする gem の lockbox のキーローテーションで躓いた件

2 min read

こんにちは。

直近のプロジェクトで秘匿性の高い情報を扱うことになり、データベースに可逆暗号化した上で保存することになりました。

最初は ActiveSupport::MessageEncryptor を使おうと思っていたのですが、
技術顧問の @willnetさんに相談したところ、
「MessageEncryptorを使うのはよいと思いますが、素で使うのは大変なのでgemを使ったほうがよい」
とアドバイスを頂きました。
たしかにsaltをレコードごとに保つ必要があったり、暗号化や復号化にいくつかステップが必要で使いづらそうな印象があります。

そこで紹介して頂いた gem の中からlockbox を使うことにしました。

ここではその中でキーローテーションが必要となり、その実行に戸惑ったので備忘録的に紹介したいと思います。

選定理由

まず lockbox を選定した理由としては

  • 保持しておく情報はMasterkeyだけでよく、環境変数として持っていけばよい
  • 暗号化および復号化はいつもどおりattributeに代入やattribute呼び出しで実現すること
  • 開発が活発であること

という点があります

使い方は README をご覧いただければ十分にわかるかと思います。

ざっくり説明すると

  1. Masterkeyを生成し、アプリケーションが読み出せる形で設定する
  2. 暗号化したいattribute名 + ciphertext というカラムをテーブルに追加する
  3. モデルに encrypts <暗号化したいattribute名> を追加する
  4. あとはいつもどおり読み書きする

といった形になります

暗号化しているカラム名を変更してしまった場合

今回開発途中で暗号化しているカラム名を変更するということがありました。
すると変更以前に保存していたデータが復号化できなくなってしまいました。

その際にはキーローテーションというものをするのですが、その方法でつまづきました。

Key Rotation

READMEには

class User < ApplicationRecord
  encrypts :email, previous_versions: [{key: previous_key}]
end

とかいてあり、previous_key に変更前の Masterkey をいれてもうまくいきません。

実はこの key というのは Masterkey ではなかったのです。

lockbox は暗号化するカラムごとに

  • Masterkey
  • テーブル名
  • カラム名

の3つを使ってそれぞれのkeyを生成し、暗号化/復号化をしています。

Lockbox.attribute_key(table: "users", attribute: "email_ciphertext")

Master key

なのでこの場合の previous_key は

Lockbox.attribute_key(table: "<テーブル名>", attribute: "<変更前のカラム名>")

となります。

おわりに

アプリケーションを作成していると秘匿性の高い情報を保存しなければならないという場面があるかと思います。
その際にこの lockbox を使うのも選択肢の中に入れていただけたら幸いです。

まだまだ lockbox を使いこなせていないので、新しい発見があったらお伝えしたいと思います。

ではまた!

Discussion

ログインするとコメントできます