せてぃーずノート

Javaのイベント参加レポートとかを書いたりします。

パスワードハッシュ化にbcrypt使う理由をまとめてみた

今日やってきたセキュリティ専門家があまりにも酷かったので書いた。書いた本人はアプリな人なので細かいところが違ったらごめんなさい。

敵「SHA-256の方がアルゴリズムとして優れている。CRYPTRECのリストにも乗っている。bcryptのblowfishは最新のリストから外れている」

確かにハッシュ化するアルゴリズムだけを比較したら、SHAの方が優れているかもしれない。ただ、攻撃者はハッシュアルゴリズムに対して攻撃は仕掛けてこない。攻撃者が狙うのはパスワード。あるかないかわからないアルゴリズム脆弱性を探すより、「P@ssw0rd」のような脆弱なパスワードや短いパスワードを見つける方が簡単である。

f:id:setys:20200402232300p:plain

じゃあアルゴリズムの目的は何かというと、平文のパスワードからハッシュを生成するのに負荷を発生させて時間をかかるようにすること。そうすれば、その間にサービス運用側は流出に対処することができる。全ユーザーのパスワードをリセットして再設定するような対策が考えられる。

ハッシュ生成に負荷をかけるという観点からすると、bcryptは故意にCPUに負荷をかけるように設計されている。Argon2ならメモリにも負荷をかける。それに対しSHAはそういう設計になっていない。

SHAの場合、対象文字列の長さによって処理の時間が変わるという問題がある。詳細は以下のページを参照。

pthree.org

敵「AESで暗号化する方式もある。AESもCRYPTRECで推奨されていて安全だ」

暗号化をした場合、鍵と暗号文が流出した時点で全てのパスワードが複合できてしまう。守らないといけない物が2倍になる。ログインのような頻繁に暗号・複合が行われる処理の場合、鍵を安全に保管するのにも気を遣う。

暗号化の問題は、何よりも複合して元の平文が入手できてしまうこと。内部不正や脆弱性に大して完璧な対策が要求される。鍵を絶対安全とも言えるHSMに格納したとしても、HSM*1にアクセスできれば複合できてしまう。bcryptなら内部の人間であろうと複合はできない。

個人的な経験だけど、AESでパスワードを暗号化しているシステムは、パスワードなり暗証番号を参照するという要件がある。窓口オペレーターがパスワードを忘れた人に口頭で伝えたりする。パスワード紛失時はリセット→再設定に倒すべきだけど、そういう客に限って大体嫌がることがほとんどで辛い・・・。

敵「独自アルゴリズムを採用することも検討・・・」

優秀な数学者や暗号の専門家を雇い、数年かけて完璧なアルゴリズムを開発する金と時間とbcryptを今すぐ採用することを天秤にかけてください。

そもそも目的は完璧に破られないことではなく、流出してから対策までの時間稼ぎで。

敵「じゃあどうすればいいんですか?」

  • 長くて安全なパスワードを入力できるようにする
  • bcrypt(またはargon2)を採用する
  • MFAを義務付ける

セキュリティに関しては、余計なことを考えずにグローバルスタンダードな権威に従っておけばいい。なんで「bcryptを使うんだろう?」って疑問に思ったら、調べればいいのです。調べれば専門の人がもっと正確に書いているものはたくさん見つかるはず・・・。

追記

あとは自分で作らないことも重要。Spring Securityとかのフレームワークを正しく使う。

*1:そもそもHSMは鍵を守るものである。暗号化対象であるパスワードは守ってくれない。HSMに金をかけるくらいならbcrypt使う方が1000倍マシで安全。