質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.32%

データベースの暗号化方法の選択

受付中

回答 6

投稿

  • 評価
  • クリップ 3
  • VIEW 3,376

morotan

score 14

前提・実現したいこと

入力されたデータを暗号化してデータベースに登録、登録したデータを部分一致検索で表示するようなシステムを作ろうとしているのですが、こういった場合どのような暗号化の方法を取るのがベタでしょうか。

開発言語はjavaで、データベースはSql Serverを想定しています。
システムとしては、画面で入力された氏名と住所を暗号化してデータベースに保存するというものです。

暗号化の方法を考えたとき、私は最初にJavaのシステム側(JavaのCipherクラスとかその他有名な暗号化ライブラリ)で入力内容を暗号化し、暗号化したものをデータベースにINSERTすればいいと考えました。

しかし、この方法だと仮に氏名や住所を部分一致検索して表示するという機能を作ろうと思ったときに、データが暗号化されているため検索できなくなってしまうと思いました。
Javaシステム側で全てのデータをSELECTで持ってきた上で一つ一つ復号して一致するか調べようかとも思ったのですがあまり賢くないような気がしたのでほかの方法を探したところ、
SQL ServerにはENCRYPTBYKEY関数やENCRYPTBYPASSPHRASE関数といったデータを暗号化できる関数が用意されていると知りました。

こういった、データベースエンジンの用意する暗号化関数を利用すれば、部分一致検索もできるらしいというのはわかったのですが、色々調べていると暗号化された列を検索するのがそもそも良くないといった話も見かけて何を選ぶべきか迷ってしまいました。

プログラム側で暗号化する場合とデータベースエンジンの関数で暗号化する場合の使い分けや、メリットデメリットについて教えていただけるとうれしいです。

見てたところ
個人情報を守るためのデータの暗号化とユーザビリティ
PHP+MySQLでのデータの暗号化、セキュリティなどについて
第3回 個人情報保護法とIT (3) 暗号化|これからの銀行を支えるIT戦略

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 6

+2

プログラム側で暗号化する場合とデータベースエンジンの関数で暗号化する場合の使い分けや、メリットデメリットについて教えていただけるとうれしいです。

ざっと以下のようになると思います。実装方式や製品によって変わる可能性はあります。

プログラム側で暗号

  • SQLインジェクション等で外部から侵入された際にデータを保護できる可能性がある
  • プログラミングはやや煩雑となる
  • 暗号鍵の保存場所や保存方法が課題
  • 検索やソートはほぼできない(完全一致検索はできる場合がある)

データベースエンジン側で保存

  • SQLインジェクション等で外部から侵入された際のデータを保護は期待できない
  • プログラミングは変更する必要なし
  • 暗号鍵の保存場所や保存方法はデータベースエンジン側で提供される(DBによるかも)
  • 検索やソートが可能(一部制約あり)

ということで、そもそもなぜ暗号化をするのかという目的に立ち返らないと、どちらの方式を採用するかは決められません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

以前postgresで実現した時は、DBで暗号化してinsertし、selectのWhere句で複合して、正規表現で部分一致をしたことが有ります。
但し、性能はかなり悪くなります。

プログラムで実現しようとすると、性能は更に悪化すると思うので、DBで対応するのが良いではないでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

プログラム側での対応はデータ量の増大に耐えられないと思われます。

なぜ暗号化したいのかという理由にもよるのですが、各種DBのTransparent Data Encryption (TDE)を利用するのが現実的な解法かと思います。

透過的なデータ暗号化 (TDE)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

以前、プロジェクトでDBの暗号化を検討してやめたことがあります。
理由としては

1) 検索性能が劣化する
2) DBを暗号化しても、SELECT結果はデコード済みである(結局そこが漏洩しないように対策が必要)
3) DB自体が暗号化されているメリットは、ディスクが盗難にあった際に簡単にそれが読み取られないことぐらいで、それなら警備員を立てた方がコストメリットがある

というのが、各有識者の意見で、それに基づき、アーキテクチャ設計の段階で採用を取りやめました。
直接の回答になっていなくて申し訳ないのですが、暗号化しない、というのも一つの選択肢かと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

SQLServerの暗号化方式
https://docs.microsoft.com/ja-jp/sql/relational-databases/security/encryption/encryption-hierarchy

階層的に組み合わせて利用しますが、
最適なパフォーマンスを得るには、証明書や非対称キーではなく、対称キーを使用してデータを暗号化します。となっています。

透過的暗号化は、Enterprise Editionが必要。

SQL Serverが持つ暗号化関数は、暗号化対象の値が同じ値でも、暗号化関数を実行する度に結果が異なる仕様のようです。
部分一致検索は、
暗号化した値では検索できないので、復号して検索することになります。
その際はインデックスが利用できないので、テーブルスキャンとなってしまいパフォーマンスが劣化します。

完全一致検索の場合は
検索が必要な項目に対してハッシュ関数を使用しハッシュ値を取得、DBに登録し、この項目に対して検索を行います。
このようにすることで、索引を使用した高速な検索が可能になります。
ただし、完全一致検索のみが可能で、大文字小文字の違いでも検索ができません。
ハッシュ値を取得するときは、ソルトを付与することを考慮して下さい。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

AP側とDB側のどちらで暗号化/複合化するかということについては、
厳密には入力する画面とDBまでの通信経路も暗号化(https等)する必要があるということなので、
それを前提にすれば、DB側で行うのが自然だと思います。

最近postgresで暗号化を行いましたので、事例として参考になれば。

暗号化する項目というのは大体が個人情報で、個人を特定する検索では、
必然的に暗号化項目に対して検索することになります。

ある程度、検索性能を担保したかったので、複合化した項目でのインデックスを作成し対応しました。

このインデックスはファンクションインデックスで、インデックスの中身は複合化されているので、
DBMSの内容まで熟知している人であれば解析可能ですが、そこは検索性能とのバーターとしました。

インデックスを作成しない状態での検索であれば、複合化した項目との比較になるので、
複合化する時間もオーバーヘッドになります。

ファンクションインデックスを作成したことにより、データベースのバックアップ、リストアについても手順が必要になりました。

概して、バックアップデータの内容も暗号化されているので、リストアを行った後に、ファンクションインデックスの作成を行う必要があったのです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる