ついに来た！MongoDBの検索可能暗号ベータ版リリースを最速で考察！！

**@kenmaro**です。
普段は主に**秘密計算、準同型暗号などの記事について投稿しています**。
秘密計算に関連するまとめの記事に関しては以下をご覧ください。

> - [秘密計算エンジニアを始めて２年半が経った。](https://qiita.com/kenmaro/items/48059dd60f79e80f5ef8)
> - [秘密計算エンジニアを始めて3年が経った。](https://qiita.com/kenmaro/items/a1d90a074d552b7bf886)

#### 勝手に秘密計算アドベントカレンダーについて

この記事は

https://qiita.com/kenmaro/items/3e8a124ce4306fe040dc

の「１日目」の記事
としようかと思っています。
興味のある方はアドベントカレンダー参加してみませんか？
ご連絡お待ちしております。

## 概要

MongoDB は言わずと知れたSaaS型のDBサービスです。
ドキュメント指向データベース、もしくはNoSQLとも言われるタイプのデータベースです。

https://www.mongodb.com/cloud/atlas/lp/try2?utm_content=rlsavisitor&utm_source=google&utm_campaign=gs_apac_rlsamulti_search_core_brand_atlas_desktop_rlsa&utm_term=mongodb&utm_medium=cpc_paid_search&utm_ad=e&utm_ad_campaign_id=14412646476&adgroup=131761130812&gclid=CjwKCAjw7vuUBhBUEiwAEdu2pBQ4IOlTXk-xf7_B_8edqZnsQkBERhlLtOKG2R_LyIXIhRr3gskXlRoCag4QAvD_BwE

今回は、このMongoDBが、検索可能暗号を正式にサポートし、ベータ版として提供を開始した、
という記事を見ましたのでそれについて少し解説しようと思います。


## 忙しい人のために

- MongoDBという世界最大規模のクラウド型DBが、検索可能暗号をサポートし、ベータ版として公開したよ
- これがリリースだよ

https://www.mongodb.com/blog/post/mongodb-releases-queryable-encryption-preview

- リリースの内容、言葉の意味やチュートリアルなどの解説を見たい人は下にまとめたよ



## 専門用語についておさらい

内容を理解するために、サクッと専門用語をおさらいしてみようと思います。

### NoSQLとは

NoSQLに関しては、RDSと呼ばれるテーブル型のDBとは異なり、
JSON（Pythonでのdictionary や、nodejsのMap型など）型をそのまま保存できるような形式です。
もしFirebaseを使ったことがある方がいらっしゃったら、FireStore、Real Time Database はいずれもNoSQLです。


### 検索可能暗号とは

一言で言えば、その名の通り
「検索が可能」な暗号を用いてデータを保存する、という方式をサポートした、
ということです。

検索可能暗号に関しては結構前に記事を書いていました。

https://qiita.com/kenmaro/items/1a57866137a6fe668f7c

興味のある方は是非ご覧ください。


## 従来技術のおさらい

リリースの価値について理解するために、
今までDB内のデータの暗号化がどのように行われていたのか、すこしおさらいしてみましょう。

#### 従来のDB暗号化について（透過的データベース暗号化：　TDE)

https://it-trend.jp/encryption/article/64-0074

こちらの記事などにまとまっている通り、
従来のDBのセキュリティを高めたい時、
データそのものをマスターキーを使って暗号化（AESを使います）し、データを保存するという手法が使われていました。（透過的データベース暗号化と呼ばれます）

この際、クエリをDBに対して発効した時（つまり検索したい時）、
一度このマスターキーを使用して暗号を復号し、検索結果を返却していました。
そして、その処理が終了したタイミングでマスターキーを用いてまたデータを暗号化して保存しておく、と言う流れです。


#### 検索可能暗号を使うと、、？

検索可能暗号を使うと、検索時（クエリを処理している間）も、
暗号状態を解くことなく処理が可能になります。
つまり、処理時に一度マスターキーを使って暗号を復号する必要がなく、
平文のデータが晒されてしまう時間帯をなくすことができます。

#### 鍵とデータの同時流出を防ぐ

また、マスターキーで一度復号する必要がないため、
DB側で鍵を保持しておく必要もありません。
復号するときはもちろん、暗号化されたデータのすぐ近くにマスターキーを持ってくる必要があるため、
そこを狙い撃ちされて攻撃された場合、データと鍵が同時に流出する可能性もあったわけですが、
検索可能暗号を用いればそのようなリスクを回避できると言うわけです。

#### 鍵はユーザが管理できる

したがって、鍵はDBのデータとは離れたところにおいておけばよく、
ユーザが管理することができます。ユーザは自身で作った鍵を使ってデータを暗号化し、
DBに登録します。DB側はユーザの鍵に触ることは基本的にない（できない）ということになります。

#### BYOK

このように、ユーザが自身の鍵を作り、それを使ってデータを暗号化して保存できるシナリオを
BYOK（Bring Your Own Key) と言ったりします。


## リリース記事のまとめ

では、いきます。
MongoDBによる公式リリース記事のポイントを箇条書きします。

- 我々は検索可能暗号DBのプレビューリリースを本日2022/06/07に行う
- 一致検索がプレビューとして使用可能
- レンジ検索（大小比較）、接頭語接尾語、部分一致そしてプラスアルファの機能がComing Soonである

ここで、一致検索のサポートはそこまで驚きませんが、
接頭語や接尾語の検索、部分一致などの機能が準備中というところはすごいです。
一般的には一度データを暗号化すると部分一致などの検索は不可能なので、前もって部分一致が可能なようにデータを整形して暗号化する必要があると考えられますが、そこはパフォーマンス（データ量やクエリの実行速度）とのトレードオフになると思われます。
しかしながら、これらを正式にサポートしているDB製品は世の中にありませんので、価値があると思います。

構成はこんな感じ。

![Screen Shot 2022-06-08 at 13.26.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519792/feff01f4-24c2-346e-2264-25fa1ffa480e.png)

書いてあるシナリオは、クエリを打つことを許可されたユーザが、SSN(米国のマイナンバー）を一致検索したいときのプロセスの流れ。


1. ドライバー（真ん中の緑枠）が、クエリを分析
2. KMSなどの鍵管理システムから鍵を取得し、クエリ自体を暗号化（詳細にはwhere句を暗号化）
3. ドライバーはDBに対して暗号化されたクエリを送信
4. 暗号状態のままDBはクエリを実行
5. DBは暗号化されたままの結果（一致検索の結果）をドライバーに返却
6. ドライバーによって結果は復号され、ユーザへと返却


となっています。


要は、

- 基本的にユーザは普通のクエリを発行
- ドライバーがいい感じに暗号化してくれて、DBには暗号化されたクエリが届く
- DBは暗号化されたデータに対して暗号化されたクエリを実行
- ドライバーに対して暗号化されたデータを返却

するので、ユーザは今までMongoDBを使っていた時のように、なにも気にすることなくクエリを実行することができ、そこに検索可能暗号と呼ばれる新しいセキュリティを付加できるわけです。


## 検索可能暗号搭載のMongoDBマニュアルを読んでみる

ここからは、リリース記事にも付与されている、仕様や使い方などが書かれた公式マニュアルを読み、
要点についてまとめてみます。

こちらのドキュメントになります。

https://www.mongodb.com/docs/upcoming/core/queryable-encryption/queryable-encryption/



### セットアップ

２種類存在。

- 自動暗号化（暗号化するフィールドについて、勝手にやってくれます。）
- 自分でカスタマイズ（MongoDBのドライバーに使用されているライブラリを用い、暗号化フィールドに対してカスタマイズできます。）

結局、この自動暗号化というような、専門性の排除をおこなってくれているところが素晴らしいと感じます。
暗号をはじめとしたセキュリティ分野は考えるレイヤによっても異なりますが非常に専門性が高いため、
このような「いい感じに」やってくれるモードが準備されていることは開発者としての親切さが見えます。
素晴らしい。


## サポート機能

少しだけ言及した方がいい用語があったので書きます。

`transparently encrypted and decrypted` 
透過的暗号化、復号ということです。先ほどTDE（透過的暗号）でも出てきたこの「透過的」
と言う意味は、基本的に「ユーザに対して暗号化していることを意識させない」という意味で使われています。

`Deterministic Encryption`
決定的暗号、と言う意味です。決定的暗号において、同じ平文を暗号化すると常に同じ暗号が吐き出されます。
たとえば「apple」という単語を決定的暗号を用いて暗号化すると、常に同じ暗号結果となります。

`Indeterministic Encryption` もしくは　`Randomized Encryption`
上の決定的暗号とは異なり、この「非決定的暗号」、「ランダム性のある暗号」
については、同じものを暗号化しようとしても、毎回違う結果が吐き出されます。

`Frequency Attack`
頻度攻撃、という意味です。
非決定的暗号の方が、決定的暗号よりセキュリティは高いのですが、その理由として、決定的暗号に対してはこの頻度攻撃が使えるためです。
例えば、ユーザがいつもapple という単語を検索していた場合、決定的暗号を用いていると
DBはいつもこのユーザは同じ単語を検索しているな、という情報を得ることが可能になってしまいます。
一方で、非決定的暗号であれば、たとえユーザが同じ単語を検索していたとしても、DBは毎回違う暗号文を見るため、同じ単語を検索しているかの分析（つまり検索ワードの頻度分析）をすることは不可能です。

### MongoDBの検索可能暗号では非決定的暗号を使用
見出しの通り、MongoDBの今回のリリースでは、非決定的暗号を検索可能暗号としてサポートしています。
この時、毎回違う暗号文が吐き出される非決定的暗号を使っては、一致検索などできないじゃないか、
と思われた方は、まさに鋭いご指摘です。
ここについては、おそらく

- 決定的暗号と非決定的暗号をどちらも使用した、２層の暗号化

をドライバーで行なっているのではないかと考察します。
これは、検索可能暗号の始祖、MIT発のCryptoDBという論文にも書かれています。（興味のある方は以下の論文です）

https://people.csail.mit.edu/nickolai/papers/popa-cryptdb-tr.pdf

この論文のFigure3なのですが、暗号が機能に応じて何層にも重ねられていることがわかると思います。
この層が玉ねぎのように見えることから、MITの論文では「Onion layers encryption」などと呼ばれています。
![Screen Shot 2022-06-08 at 14.10.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519792/9ec2c90e-76af-f24b-360d-b8e980685615.png)

このように、MongoDBの検索可能暗号についても、検索可能性を担保するためにいくつかのレイヤを設け、
一番外のレイヤにランダム性を持たせることで一見ランダムに見えるデータをメタデータとして保存していると考えられます。
これはマニュアルのここの記述からも考察できます。

![Screen Shot 2022-06-08 at 14.07.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519792/1022bf46-1b5e-d8f3-e76c-503be2c0f447.png)

検索可能対象としたいフィールドについては、

`__safeContent__`

をメタデータとして明記する必要があるとのことですが、次のところで
検索可能暗号はメタデータコレクションとして、３つのコレクションを同じDB内に作成します、
とあります。
これらのメタデータは、用途に応じて（つまりクエリの種類に応じて）使い分けられると考えられるのですが、
それぞれ違う構成の暗号、もしくは先ほどの暗号層の構成をもったデータと考えられます。


## AWS, Azure, GCP などの主要鍵マネジメントサービスに対応

ドキュメントのこの箇所に言及されていますが、

![Screen Shot 2022-06-08 at 14.15.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519792/1c611175-d295-7ca5-f5f6-f7bc2806eaf2.png)


検索可能暗号を使う際には、外部（つまりMongoDBが管理しない）の鍵マネジメントサービスが必須となっています。
理由は、データを管理するMongoDBが鍵を発効してしまっては、鍵とデータの分離がもちろんできないからです。この観点関しては、先ほどのBYOK（ユーザが自身で発効した鍵を持ってくるという意味）の説明にも書きました。



## まとめ

結構長くなってしまったので、一旦ここでまとめます。

検索可能暗号は、パフォーマンスの低下などのトレードオフに対して一旦目を瞑れば、

TDE（透過的暗号）型のDBのセキュリティ上の上位互換となります。

MongoDBがこれを公式にサポートした（まだプレビュー版、ベータ版と考えて良い）
ということはかなり大きなことだと思います。

個人的にもMongoDBはウェブアプリ開発の時に使ったことがあり、好きなサービスだったのでこのようなサポートは嬉しかったです。ですので今回考察記事としてこの記事を書かせていただきました。


次回は、実際に検索可能暗号を彼らのクイックスタートを追って実装（というか利用）してみようと思います。そこまでこの記事に書くと少しボリュームが多くなりそうだったので別記事にします。


というわけで実際に動かしてみた記事も是非ご覧ください、！！

追記　以下に公開しました。

https://qiita.com/kenmaro/items/2185d5402b2e33eb8204



今回はこの辺で


@kenmaro