sontixyou blog

技術まわり、ガジェット関連について

Active Recordのカラムの暗号化でソートできずにハマった

背景

記事のタイトルを保存するtitleカラムがあるとします。このtitleカラムは、記事一覧ページでtitleの並び替え機能があるとします。
あるとき、Railsで文字列を保存するtitleカラムを暗号化しようと話題が出ました。

カラムの暗号化

Railsには、2種類の暗号化が用意されています。

カラムを並び替えしたい

以下のレコードをencrypted_titleカラムを指定して、並び替えしたいとします。

mysql> select id, encrypted_title, title from posts;
+----+--------------------------------------------------------------------------------------------+---------+
| id | encrypted_title                                                                          | titile |
+----+--------------------------------------------------------------------------------------------+---------+
| 38 | {"p":"PCAd","h":{"iv":"0/OwqRAVpqf4HXBP","at":"CgzTlnJnc89XS+alEZ3G7Q=="}}                 | 123     |
| 46 | {"p":"PCAd","h":{"iv":"0/OwqRAVpqf4HZGE","at":"CgzTlnJnc89XS+alEZ3G7Q=="}}                 | あかさたな     |
| 47 | {"p":"PCAd","h":{"iv":"0/OwqRAVpqf4HABC","at":"CgzTlnJnc89XS+alEZ3G7Q=="}}                 | 一覧     |
| 48 | {"p":"PCAd","h":{"iv":"0/OwqRAVpqf4HABC","at":"CgzTlnJnc89XS+alEZ3G7Q=="}}                 | 一蘭     |
+----+--------------------------------------------------------------------------------------------+---------+

普段なら、次のようなコードで並び替えをします。

Post.all.order(encrypted_title: :desc) # titleカラムを降順で並び替えた結果と同じになってほしい。

このコードを実行しても、titleカラムを降順で並び替えた結果と同じにはなりません。
なぜなら、encrypted_titleの暗号化された文字列で並び替えをされてしまうため。上のコードを実行したタイミングでは、encrypted_titileは復号化されていません。。。

並び替えするには。。。

次のようなコードを実行する必要があります。自分が求めている並び替えをSQLでできないため、Rubyの世界で並び替えをやります。

Post.all.sort_by { |p| p.encrypted_title }

しかし、この手法にはパフォーマンス悪化の懸念があります。 例えば、postsテーブルに10万件レコードあるとき、Rubyの世界での並び替えはSQLでの並び替えより速度が劣るはず。
なので、どうしようもないときの最終手段で用いたほうがいいと考えています。

最後に

今までカラムの暗号化するのは、センシティブな情報を含むパスワード等しかやったことがなかったです。
今回の事例で暗号化の理解や並び替えについての知識を身につけられたのはよかよかです!