Michinosuke
@Michinosuke (みちのすけ)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

電話番号をデータベースに追加するときのハッシュ化のアルゴリズムの選択

ログインに電話番号を使用したいので、データベースには電話番号をハッシュ化して保存しようと思っています。

通常、パスワードをデータベースにハッシュ化して保存する場合、PHPのpassword_hash() 関数で、個別にランダムなソルトを追加し、bcryptをコスト10以上で使用すれば、問題ないという認識でいます。

しかし、電話番号の場合、基本的には11桁の数値の固定長なので、bcryptでは十分ではなく、hash_hmac() 関数でHMAC-SHA256を使用した方が良いのでしょうか?

HMACでは、秘密鍵が漏れない限り、ハッシュ化された文字列からの復号は現実的な時間で不可能だという認識でいます。

実現したい安全性は、万が一、データベース上から電話番号のハッシュがソルトと一緒に流出した場合に、現実的な時間(電話番号一つあたりの解析時間が10年以上)で、特定のユーザの電話番号を解読されないというものです。

HMACを使用した方が良いと思ったのは、以下の記事を読んだからです。
ハッシュ化された電話番号を解読するのは簡単ですか?

私は暗号について詳しくないので、間違っているところがあればご指摘お願いいたします。

[追記]
teratailでも同様の質問をさせていただき、徳丸さんに分かりやすい解答をいただいたので、こちらの質問内容に興味のある方は、そちらも合わせてご覧ください。
https://teratail.com/questions/333883

0

3Answer

セキュリティについて素人の私が良い悪いを言うのは良くないと思いますが。

password_hash() (bcryptなど)の場合には、公開ソルト+遅いハッシュでガードする、という意味だと思います。

一方、hash_hmac() の場合には、非公開鍵(≒非公開ソルト)でガードすることになると思います。

情報漏洩の場合に、非公開鍵が一緒に漏洩しないとは言えないため、根本的な対策にはならないと思います。

Qiita の記事で以下のようなものがあります。

この記事のコメントで徳丸さん @ockeghem (セキュリティ関係の本も書かれている、セキュリティに詳しい方です)が以下のようにおっしゃっています。

加えて、秘密のソルトを用いたとしても、その秘密が隠せるとは限らないという事情があります。
なぜなら、パスワード情報が漏えいした局面で、ソルトは隠しおおせるとは限らないからです。ウェブサイト等がOSコマンドインジェクションなどで任意プログラム実行可能な攻撃ができたばあい、攻撃コードはウェブアプリケーションと同じ権限で動作します。なので、ウェブアプリケーションからは秘密ソルトを読み取れるが、攻撃コードからは読み取れないという仕掛けを作ることは困難です。
なので、ソルトを隠すことは、さっぱりとあきらめるという実装が多く用いられています。

一般的なセキュリティの話としては、hmacなどのメッセージ改ざん防止のハッシュ機構を使ってパスワードのハッシュを作るのは良くない、bcrypt などを使うのがベストプラクティス、だと思います。

そもそもの話として、電話番号をパスワード代わりに使用する、という意味なのでしょうか?
そうだとしたら、11桁(固定電話なら10桁)の数値のみという項目をパスワードにすることそのものが問題なのだと思います。
(現在のパスワードのベストプラクティスは、とにかく長めのパスワードを使う、だと思います)

パスワード+電話番号で認証しようとして、電話番号もそのまま持たないでハッシュする、という意味ならまだわかりますが(その場合には、素人考えではパスワードと電話番号を合わせてbcryptなどでハッシュすればよいのではないか、と思います)

2Like

Comments

  1. ちょっと追記します。

    電話番号をハッシュして保存というので、パスワード相当の扱いだと思って以前のコメントを書きました。

    一般的と言っていいのかどうかわかりませんが、私のわかる範囲だと、通常電話番号はハッシュ化をしないで、データーベースに保存することが多いかと思います。

    それは通常、電話番号は利用する(顧客に問い合わせの電話を掛けたり、SMSを送ったりする)ために登録するので、一方向ハッシュをしてしまうと使えなくなってしまうためです。

    そのかわり、その他の個人情報と一緒に、個人情報保護の施策をうつことになると思います。

    https://www.ipa.go.jp/security/kojinjoho/

    ただし、そのあたりの判断はプロジェクトごとで決めるものだと思いますので、かならずしも電話番号をそのまま登録すべし、という話ではありません。

    今回の想定では同一電話番号チェックをしたいということであれば、当然ハッシュ化自体は可能だと思います。

    ただ、電話番号について bcrypt などのハッシュでも安全でとは言えないと判断した場合に、 HMAC を使ってもセキュリティが上がるとは言えないというのは、前のコメントの通りです。

    (私の)結論として「電話番号自体を保持するという考えが間違っていた」わけではないと思います。
    平文のまま電話番号を持つか、ハッシュ化なりして持つかは選択肢としてあると思います。
    ただし、電話番号を保持して情報漏洩したときに解析時間に10年を見込める方法は難しい(多分ない)と思います。
  2. @Michinosuke

    Questioner

    追記ありがとうございます。
    具体的に書いていただいて、とても嬉しいです。

    おっしゃられている通り、ハッシュ化してしまえばこちらからメッセージ等送れなくなってしまうのは不便ですね。
    ハッシュ化して持っても根本的な解決にならない以上、ハッシュ化する必要はあまりないかなと考えを改めました。
    むしろハッシュ化することで「万が一漏洩しても大丈夫」のような気持ちになってしまうのであれば、逆効果かなとすら感じました。

    今後はプロジェクトの内容と合わせて、個人情報保護に配慮した上で平文で持つのか、もしくはSMS認証自体をやめておくのか検討したいと思います。

    大変丁寧に教えていただきありがとうございました。

@yoshi389111さんの意見に全面的に賛同しますが、追加で。
DB流出からの電話番号割れを危惧されてるみたいですが、それより先に「組み合わせ総数が少なすぎてブルートフォース(総当たり攻撃)で速攻で破られる」問題が来ると思います。
上司や顧客がやれと言い張ってる場合、上で翻意するように説得して、どうにもならないようであれば接続制限めっちゃ厳しくする(1時間あたり5回までとか)とかですかね……。

1Like

@yoshi389111 @u83unlimited
お二人とも、とても分かりやすい説明ありがとうございます。

HMACが万能のように考えていましたが、ご指摘の通り、データベースの内容が漏洩するような状況下で、秘密鍵が漏洩しないとは言えませんよね。

電話番号はSMS認証で使用しようと思っていました。
SMS認証を行なった上で、電話番号のハッシュを保存し、新たにSMS認証をしようとした場合に、すでにSMS認証をしたことがある電話番号の場合は、認証できないようにするようなものです。
が、そもそも電話番号自体を保持するという考えが間違っていたようです。

もしSMS認証するなら、is_phone_number_authenticatedのようなカラムを設けるに留めたいと思います。
その場合、複数アカウントで同一の電話番号を認証されることは防げない、ということになると思いますが、仕方ないですよね。

それでも重要性としては、一つの電話番号で複数アカウントを承認されてしまうことより、ユーザの情報を守ることの方が重要なので、前者は諦めようと思います。

0Like

Your answer might help someone💌