機密情報を取り扱うシステムに携わり、「余人はおろか保守運用担当者にすら容易には触れさせたくない」ような情報の秘匿について考える機会があった為、そこで得られた知見についてつらつらと書いていきます。
暗号化対象データの在処について - 通信路
クライアントにあたる端末からサーバまでの経路については改めて語るまでもなく、世の多くのシステムはHTTPSによって暗号化が図られていると思います。が、殊更に内部犯に対しても慎重を期して臨む場合は、アプリケーションサーバとデータベース間、SSL終端サーバとアプリケーションサーバ間の通信でさえ、人々が容易にアクセス可能なネットワークを流れないようにルーティングの検討が必要な場合があります。前者はDBMSのセキュア通信機能を利用する、後者はそもそもSSL終端サーバとアプリケーションサーバを1ホストに同居させてUNIXドメインソケットで通信する、等といった対策も考えられます。
クラウドサービス上に構築するシステムであれば、VPCとセキュリティグループ/ファイアウォールルール等で閉じ込める、といった方法が簡単・確実だと思います。
※ 意図的でもない限りまず発生しないとは思いますが、平文の通信がパブリックネットワークや外部ネットワーク上を流れないようにも注意しましょう。
暗号化対象データの在処について - ストレージ
データが永続化される場所に関しては、暗号化によって守るべき対象と手段は複数あります。
- ハードウェアによるドライブまるごとの暗号化(自己暗号化ドライブ等)
- 低レベルなソフトウェアによる全データの暗号化(Check Point Full Disk Encryption等)
- データストアミドルウェアによる透過的暗号化(Oracle DBのTransparent Data Encryption等)
- アプリケーションの実装による明示的な暗号化
1、2は稼働中のシステムにおいては誰にとっても透過的な措置であるため、アクセス可能=解読可能であって、(物理ホストマシンからドライブごと抜き取っての盗難等の物理的な犯行以外には)ほぼ無意味です。最低でも3or4、乃至は3&4の併用が高度なセキュリティを要求されるシステムには必須になります。
さて、アプリケーションの実装による暗号化における、暗号化方式や鍵の管理運用といったメジャーな観点は余所に譲って、ここでは比較的日の当たらない、けど地味に痛し痒しなポイントについてもう少し深堀りします。
非透過的な暗号化を施されたデータは検索条件に出来ない
平文で「田中一郎」という氏名であったデータが暗号化されて「AAAXXXZZZ」となって記録された場合、当然ながら「氏名="田中一郎"」という検索条件では文字列が一致しないため検索にヒットしません。では「田中一郎」を再び暗号化した文字列を指定すればよいのかというと、昨今の主流な暗号化方式では暗号化の都度毎回異なる暗号文が生成されるため、「氏名="QQWWEWEEE"」等となってしまいやはり検索できません。かくなる上はデータベースからは全件持ってきてしまって1行1行復号!…は流石に富豪的発想が過ぎるので最終手段に取っておくとして、それよりは幾らかマシな性能が出る方法を考えてみます。
まず保存時には
- 暗号化したい項目の平文を一定のルールで加工する
- 加工後の値をハッシュ化する
- ハッシュ値を一定のルールで加工し、元の項目とは別項目に保存する
具体的には、例えばこんな要領です。
- 氏名の1文字目~3文字目を抜き出す 「田中一郎」→「田一」
- ハッシュ化する 「田一」→「sfhkrkuy24hrifulhuiwh4igt」
- ハッシュ値を文字列化し5文字目から10文字目を「氏名ハッシュ」なる項目に保存する 「sfhkrkuy24hrifulhuiwh4igt」→「kuy24」
こうして記録したデータは、次の手順で検索可能になります。
- 検索条件として入力された文字列に上記1~3と同じ手順で加工を加える 「田中一郎」→「kuy24」
- 加工した文字列でデータベース上を検索する →目当ての「田中一郎」のレコードの他、偶々計算結果が「kuy24」となって被る複数のレコードが余分にヒットする。
- 検索結果から本来検索したかった項目の値を取り出して復号し、検索条件として入力された元の値と一致するレコードのみに絞り込む。
※ このような平文の代替値(これもサロゲート値と呼ぶんでしょうか…)を用いた処理は、加工方法に応じて平文推測の難度と応答速度に影響を及ぼします。加工を手薄くすればするほど旧いECB方式のように代替値から平文を推測し易くなります。
※ 部分一致検索?諦めましょう。 こんなのがあるそうです:「 三菱電機、「部分一致対応秘匿検索基盤ソフトウェア」を開発」
要暗号化!とジャッジしたからにはあらゆる場所で死守しなければならない
当たり前の事なのですが意外と忘れられがちだと思います。何の事かと言うと、ログです。
Webサーバのアクセスログやアプリケーションサーバのデバッグログ、監査対応の証跡用ログなど、普段ならデータ容量に割ける予算の限りリッチに出力しておきたいログ情報が一転して、「露出し過ぎ」に注意すべきなポイントになります。
ログ出力時にも律儀に手堅い可逆暗号化を仕掛けるという手も無くは無いですが、ログであれば対象項目値を暗号化ではなく「*****」のように一律マスクしてしまうという方法も使えます。但し当然ながらその状態では証跡としての能力を失いますので、例えば「操作した顧客の会員番号」のように証跡としては必要だがセンシティブな情報なので秘匿もしたい…というケースで困ることになります。この場合は外界でも意味を持つ「会員番号」のままではなく、「会員番号(暗号化済)を持つテーブル上の1レコードを特定可能なサロゲートキー」、即ちシステム内部でしか意味を為さない値の方をログに残すようにするという手段が考えられます。後から証跡として分析が必要になった時点でその措置に相応しい決裁と手順を経て分析する方法さえ提供しておけば目的は達する事が出来、かつ、シス管や保守運用担当が定常業務でログを覗く限りではその値から何かしら機密情報を得る事は不可能な状態を保つことが出来ます。
※ ログのログたる所以はその情報が"ある時点の断面"である事、でもあります。サロゲート値のみをログに残す場合、ログ日時とそのサロゲート値を使って当時の状態のデータを再現できる必要があります。
まとめ
持たなくていい機密情報は持たないに限りますね。本当。(´・ω・`)