たしかに!!
パスワード漏洩時に利用者へ連絡する必要があるというのは、考えから抜けていました。確かにそういった場合もありますし、サービス運営を進めるうえで利用者へ連絡が必要な場面がほかにもあるだろうことを考えると、メールアドレスは平文で持っていたほうが良いと思えました。
一人で考えていますと抜け漏れがありますので、意見を頂けるのは大変助かります。ありがとうございます!
メールアドレスのハッシュ化にメールアドレスを用いれば、メールアドレスをキーとして扱えるかもしれない
ソルトにユーザーIDを利用やハッシュ値を作る際にユーザ名を混ぜ込むを読んでいて思ったのだが、メールアドレスをハッシュ化する際のSALTとしてメールアドレス自身を用いれば、メールアドレスをキーとして扱うことができる気がしてきた。
素人考えなのでセキュリティ的に安全なのかはわからない。レインボーテーブルは作れてしまいそうだ。
逆の発想で、パスワードをSALTにしてメールアドレスをハッシュ化すればいいかもしれない。パスワード変更時にはメールアドレスも一緒に入力してもらう必要がある。
メールアドレスのハッシュ化に乱数のSALTを用いると、メールアドレスをキーとして扱えない
私も当初よりハッシュ化したメールアドレスをキーにする方法を考えていたのですが、結論から言うと難しいです。おっしゃる通り、ハッシュ化したメールアドレスをキーにすれば一見問題ないように思えたのですが、以下の理由から低い計算コストで実現するのは難しいと判断しました。
- メールアドレスをハッシュ化するSALTは値が毎回変わる
- 「ハッシュ化したメールアドレス」と「メールアドレスをハッシュ化するSALT」のペアは利用者の数だけ存在する
- そのため、「利用者認証時に入力されたメールアドレス」をハッシュ化する適切なSALTを、O(1)で見つける方法が存在しない
- 以下の手順を用いれば計算コストO(N)で「利用者認証時に入力されたメールアドレス」をハッシュ化する適切なSALTを見つけることができる
- DBから全ての「ハッシュ化したメールアドレス」と「メールアドレスをハッシュ化するSALT」を取り出す
- 取り出した全ての「メールアドレスをハッシュ化するSALT」で、入力されたメールアドレスをハッシュ化する
- 「DBから取り出したSALTでハッシュ化したメールアドレス」と、「DBから取り出したハッシュ化したメールアドレス」を全て突合する
- 以下の手順を用いれば計算コストO(N)で「利用者認証時に入力されたメールアドレス」をハッシュ化する適切なSALTを見つけることができる
- また、利用者登録時にもメールアドレスの重複を検査する必要があるため、『「利用者認証時に入力されたメールアドレス」をハッシュ化する適切なSALTを、O(1)で見つける方法が存在しない』という問題になる
処理の流れ
メールアドレスとパスワードを入力し、利用者を登録する(メールアドレス・パスワードをハッシュ化してDBに保存する)
- メールアドレス用のSALTを作成する
- 作成するたびに値が変わる
- mailaddress_salt_dbとする
- メールアドレスをハッシュ化する
- mailaddress_hashed_dbとする
- パスワード用のSALTを作成する
- 作成するたびに値が変わる
- password_salt_dbとする
- パスワードをハッシュ化する
- password_hashed_dbとする
- 利用者情報(mailaddress_hashed_db(主キー)、mailaddress_salt_db、password_hashed_db、password_hashed_db)をDBに保存する
メールアドレスとパスワードを入力し、利用者を認証する(メールアドレスでDBに保存したハッシュ化したパスワードを取り出し、入力されたパスワードと照合する)
- メールアドレス用のSALTを取得する
- mailaddress_saltとする
- ここで不都合が生じる。SALTは生成する度に値が異なる かつ 利用者情報のレコードが複数存在する 場合、DBに保存した際のメールアドレス用のSALTを計算コストO(1)で取得することができない。
- メールアドレスをハッシュ化する
- ハッシュ化したメールアドレスで利用者情報(ハッシュ化したメールアドレス、メールアドレス用のSALT、ハッシュ化したパスワード(password_hashed_dbとする)、パスワード用のSALT)を取得する
- 入力されたパスワードをDBのパスワード用のSALT でハッシュ化する(password_hashedとする)
- password_hashed_dbとpassword_hashedが一致していれば認証成功とし、一致していなければ認証失敗とする
あれ
メールアドレスもハッシュ化を試してみたところ、問題が一つ発生した。メールアドレスとパスワードによって認証する時、メールアドレスにSALTを付与したうえでハッシュ化しているために、利用者が入力したメールアドレスをキーとして、DBに格納されているハッシュ化したパスワードを引き出すことができない。
無理やり突合するならば、すべてのSALTを取り出して、ハッシュ化して突合すれば何とかできるが、計算コストがかかってしまう。
もしくは、メールアドレス以外に主キーにできる値を持たせられればいいが、それを利用者に覚えてもらうというのも現実的ではない。
良いアイデアだと思ったが、うまくいかないので棄却するしかない。
あれ
月額100円のPKMSを作りたい。企業内へのPKMS導入において価格がネックあるならば、安価なPKMSを作れば普及させられるはずだ。
PKMSの低価格化を目指すには、雇用をほぼ一人に絞る必要がある。雇用を一人に絞ったとき、浮かび上がってくるだろうわかりやすい問題は以下が考えられる。
■セキュリティ対応
セキュリティ対応に関してはセキュリティを低廉化し、セキュリティホールがあっても情報を漏らさない体制を作ることができればいい。極端なことを言えば、サーバーに配置されるデータがすべて暗号化もしくはハッシュ化されていればセキュリティホールによる情報漏洩リスクはかなりなくせるはずだ。
パスワードをハッシュ化するように、メールアドレスもハッシュ化すれば個人情報漏洩リスクをさらに低減させることができる。なぜ一般的なサービスでメールアドレスをハッシュ化しないというと、利用者に対するメールによる連絡が目的だからだ。つまるところ営業活動が目的である。これをすっぱり諦めてしまえばかなり安全側に倒すことができる。また、パスワードの再発行に関しては、メールアドレスを利用者に送ってもらい、そのメールアドレスに対してパスワード更新のURLを送付することで実現できる。もちろんメール送信の際にはハッシュとの突合を行う。メール送付機能が悪用されることを防ぐためだ。メールアドレスもハッシュ化は悪質な利用者の停止にも対応できる。利用停止した利用者のメールアドレスのハッシュさえ持っていれば、同じメールアドレスでの再登録を防ぐことができる。
E2EEのPKMSというのも魅力的な考え方だ。PKMSに入力されるデータは社外秘や個人情報になりうる。これらを平文で持たず、サーバー内では暗号化されていることでかなり安全になる。ただ、多対多のE2EEを実装するのはどうも難しいらしい。要研究だ。
■悪質な投稿への対応
PKMSの投稿が一般公開されている場合、普及するにつれて悪質な投稿に対する対応というものが必要になってくる。この対応は必ず人の稼働という形でコストを必要とする。そうであるならば、一般公開されず、個人・チーム内で閉じた空間での利用に限定し、さらに月100円(仮決め。正直いくらでもいい。)を支払わせることで悪質な投稿による影響や、そもそも悪質な投稿がされる可能性を低減させられる。
一般公開しないという方針は利用者が入力した情報が漏洩する危険性を発生させるが、E2EE化し、暗号化した情報のみをサーバに持たせるようにすれば安全にできるはずだ。
■問い合わせ対応
検討中。正直なところどんな問い合わせが来るか想像がつかない。安定拡大しつつ、対応する資料や仕組みを整えるしかないかもしれない。可能な限り問い合わせが来ない体制にしたい。PLGの考え方が役に立つだろう。人が問い合わせに対応するのではなく、PKMS自身に問い合わせ対応させる。そういうことができればよさそうだ。Helpfeelが参考になる。
あれ
パスワードは後生大事にハッシュ化しているにも関わらず、メールアドレスはなぜ平文で保存しているのかと、ふと気になった。サービスから利用者へのメール送信を諦めれば、メールアドレスもハッシュ化できるはずだと思うに至った。