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

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

ただいまの
回答率

90.12%

DB検索性の高い暗号化処理について(復号化の必要なし)

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 3,169

sakamata

score 141

Laravel5.6
mysql  Ver 15.1 Distrib 5.5.56-MariaDB (本番環境)
mysql  Ver 14.14 Distrib 5.7.22, (開発環境)

でアプリケーションを制作しています。

DBに個人を特定する値が入っています。ぶっちゃけると MACAddressなのですが
毎回、500件程にwhereで絞り込んだ後に、およそ100件程のMACAddressの付き合わせ検索を連続で頻繁に行う必要があります。
具体的には外部からhttpsでPOSTされて来る100件程の生のMACAddressの値と、DBの値を比較する処理をしています。

これまでDBにはMACAddressが生データで入力されており、完全一致で検索をかけていましたが、
これをhash化して管理したいと考えています。

そこで検索性が高く、いざというとき(DBデータ盗まれた等)複号化されにくい暗号化の方法としてどのようなものを使うのがふさわしいでしょうか?

まとめると以下の様な条件になります。

・DB検索に時間がかからなければ良い。
・システムとして値の複号化は必須要件ではない。(つまりopenSSL等で複号化をしないでも良い)
・DBの方では一意性が保証できる値となっていれば良い。
・DBの情報が漏洩した際、復元されにくいものが良い。
・md5,sha1 は計算力を使えば複号されるので不採用。
・Laravelファサードの Hash:check() はかなりの処理時間がかかるので不採用。

また、このような要求にこたえられるような暗号化の記述がされたサイト等あれば、
それのみでもご紹介いただけると幸いです。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • tanat

    2018/11/24 18:16

    インターネット上に公開されているサービスでの話という前提で問題ありませんか?

    キャンセル

  • sakamata

    2018/11/24 18:17

    はい、そうなります。

    キャンセル

回答 4

+8

・md5,sha1 は計算力を使えば複号されるので不採用。

という前提であれば、SHA-256でも大差はないと考えられます。MD5やSHAシリーズは、ハッシュ値の計算に高速性が求められる要件(たとえばDVDイメージのハッシュ値を求める等)に適したもので、総当たり耐性は弱いです。te2jiさんの指摘のように、MAC Addressは48ビットしかないですし、ベンダー固有の値もあるので、総当たり攻撃はやりやすい条件です。

ということで、パスワードの保存と同じように、ソルトとストレッチングを施したらどうでしょうか?パスワードの保存とは要件が異なるので、レコード毎に異なるソルトをつけることはできませんが、固定のソルトで、かつできるだけソルトを秘匿すれば、元のマックアドレスが知られるリスクを減じることができます。

PHPで実装する場合、password_hashも使えなくはなかったのですが、PHP 7.0でソルトを外部から指定することが非推奨になりましたので、crypt()関数を使うのがよいでしょう。以下は、Blowfishという総当たり攻撃に強いアルゴリズムを使った実装例です。

$mac_key = crypt($mac_address, '$2y$10$ABCDEFGHIJKLMNOPQRSTUV$');

ここで、$10$ のところはストレッチングの回数のパラメータ(回数そのものではない)ですので、実行時間を見ながら調整してください。大きいほど強度は高くなりますが、実行時間はかかります。
ABCDEFGHIJKLMNOPQRSTUVはソルトですので、ランダムな別の値にしたうえで、できるだけ外部に漏れにくい実装を工夫してください。万一ソルトが漏れても、復号には総当たりをするしかないので、それほど神経質になる必要はないと思います。
crypt()関数はバイナリセーフでないので、マックアドレスは16進数など、NULLバイトが入らないようにしてください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/11/24 21:23

    詳細な回答ありがとうございます。ソルトというものを初めて知りました。
    これまで DBに暗号化したい値を入れる際は 対象の文字列に対し、環境変数に書いたランダムな値を結合する、等の方法で暗号化/復号化/hashチェック等を行ってしましたが、きちんとした名前や作法(?)があった訳ですね。
    また`$10$`で強度を調整できることも初めて知りました。こちらもパフォーマンスをみつつ調整します。
    確かにMACAddressは解析されやすそうです。御指南いただいた方法で試してみたいと思います。
    また、とても心強い方からのアドバイスで嬉しさひとしおです。ありがとうございました。

    キャンセル

checkベストアンサー

+3

SHA-1の強度で許容されないのであればSHA-256が最有力になるのではないでしょうか。

・DB検索に時間がかからなければ良い。

については、インデックスが適切に貼られていれば問題無いでしょう。
(もしSHA-256処理によるCPU負荷が問題になるのであれば、HW性能と要件が釣り合っていないのでどちらかを変える必要がある)

(前提をひっくり返すことになりますが)
インターネット経由の通信で取得されるMACアドレスは個人や端末を特定できるものでは無い(最も個人に近い箇所でもプロバイダのルータのMACアドレスになるはず)ので、セッションIDを使ったり、cookieでクライアントを特定できるトークンを発行してそちらで特定する方が良い様に思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/11/24 19:06

    回答ありがとうございます。SHA-256ですと64文字の乱数に変換ということですね。
    検索性はアドバイスいただいた通り、DBに対して正しくインデックスを張るという事で解決しようと思います。
    また、MACアドレスについてのご指摘もありがとうございます。これはwi-fiルーター等のローカルネットワークに接続された端末のMACAddressを取得しております。つまり個人のPCやスマホ等の端末固有のものなので、ある程度の一意制が確保されています。
    とはいえ、端末によっては値を変えたり出来てしまうものだそうで、DBには一意の値としては信用しないで管理するのを前提にして設計しております。

    アプリ仕様の説明を省いてしまいますが。結論としては SHA-256 でhash化してDBでMACAddressを管理、POSTされたMACAddressを複合インデックスを張ったtable値と比較して検索性を上げる。
    という道筋が見えてきました。
    アドバイスありがとうございます!

    キャンセル

+2

・DBの情報が漏洩した際、復元されにくいものが良い。

MACAddress って組み合わせが決まってるから、総当たりでもそこそこ簡単に解析できちゃうんじゃないかなぁ。。。
stretching は必須な気がする。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/11/24 21:27

    stretching という事は、別の解析されにくい文字列等をつなげてた状態でhash化する。ということでしょうかね。確かに短くて法則性のある文字列なので、解析されやすいかもしれませんね。なので、ockeghem様のアドバイスにもありました通りソルトを付けて対応しようかと思います。アドバイスありがとうございました。

    キャンセル

  • 2018/11/24 21:46

    > stretching という事は、別の解析されにくい文字列等をつなげてた状態でhash化する。ということでしょうかね。

    違います。検索すれば、サクッと出てくるので、確認してください。

    あと、そもそもの MAC address の保存目的によっては適した手段ではないので、要件との突き合わせをし直すことをオススメします。

    キャンセル

  • 2018/11/24 23:49

    回答ありがとうございます。
    stretching とはhash化した値に対してさらにhash化を繰り返し行わせる方法ということでしょうかね。これも未知の方法でした、認識を改めます。
    https://www.slideshare.net/ockeghem/how-to-guard-your-password
    偶然というか必然というか、検索して出てきたのは他の回答者の方の資料でした。
    パスワードを解析されないようにするには向いているかもしれません、が、確かにご指摘通り今回の要件には少々不向きかもしれませんが、セキュリティに対するよい意識付けになりました。
    ありがとうございます。

    キャンセル

0

皆さまの回答でhash化や暗号化、セキュリティに対する意識をいっそう強く持てる様になりました。
ひとまずWebサーバー側でアドバイスいただいた様に不可逆暗号化して、DBに値を入れる様に実装しましたがやはり暗号化する際のパフォーマンス低下が気になります。そこで、外部から生のMACAddressをPOSTさせて暗号化させるより、その外部自体で先に暗号化をさせてからPOSTをさせた方が、圧倒的にパフォーマンスが出ることが明らかなので、以下のページなどを参考に今回のアドバイスを生かした暗号化をローカル環境のデバイスの方に施そうと思います。

https://ten-snapon.com/archives/1399
回答ありがとうございました。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/11/26 01:02

    度々すみません。返信の際の最後におっしゃられている『総当たり』とはDBの全件検索という事でしょうか?それを前提とするのであれば、問題は無いと考えています。 MACAddressをPOSTする際に、どのクライアントからの情報であるかも付与してPOSTしているので、クライアントに存在する100件程のレコードに絞り込んだ状態での検索となります。

    キャンセル

  • 2018/11/26 06:32

    ちょっと勘違いしていまして、「総当たり」は必要ないですね。失礼しました。
    しかし、端末毎に固有のソルトをもつくらいであれば、te2jiさんが指摘されたように、端末毎に固有の値を記憶するほうがよいのではないでしょうか? UUIDがこの目的に適していると思います

    キャンセル

  • 2018/11/26 14:47

    いえいえ、私の説明が下手で誤解をさせてしまっているようです。すみません。
    UUIDを初めて知りました。確かに固有IDを取得してMACAddressと紐づけするという方法も良いですね。
    ただ、クライアント側のプログラムはなるべく簡単なもので、値等もなるべく保持しない事を前提にシステムを設計しています。実はクライアント側は arp-scan をかけてサーバーに定期的にPOSTしているのみの単純なshellスクリプトです。ここにMACAddressとUUIDとの紐づけをするとなると、クライアント側に情報を管理記憶させる処理が必要となりますのでそれは避けたいのです。
    また、別の方法としてクライアント側でMACAddressを生でPOST、サーバー側でUUIDに変換して保存、という処理をしたとしても、POSTされる都度、サーバー側で毎回UUIDに変換してから(別の値が発行されてしまう?)値の検索をかける。という事で二度手間的な処理が発生しますので、これもあまり得策ではないかもしれません。
    なので現状は クライアント側で arp-scan をかけ、 MACAddressを shasum 256 にソルトを付けてhash化してPOSTさせ、その値をサーバー側で保持するのが、最適と判断します。
    色々と丁寧なアドバイスを本当にありがとうございます!

    キャンセル

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

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