Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Why Developers Should Stop Hashing Passwords and Start Using KDFs

2025年10月02日に「Dev.to」が公開したITニュース「Why Developers Should Stop Hashing Passwords and Start Using KDFs」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

パスワード保存にSHA-256などの従来のハッシュ関数は、高速なため攻撃されやすく危険だ。ユーザーの安全のため、パスワード保存に特化した鍵導出関数(KDFs)を使うべきである。Argon2idやbcryptなどが推奨されており、これらはパスワードクラッキングを遅らせ、セキュリティを向上させる。

ITニュース解説

システム開発において、ユーザーのパスワードを安全に管理することは非常に重要な責任だ。これまで、「パスワードを平文(そのままの形で)で保存せず、ハッシュ化する」という原則が広く守られてきた。これは確かに第一歩として正しかったが、現代の技術進歩とセキュリティ脅威を考えると、2025年現在ではこの「ハッシュ化」という考え方だけでは不十分で、かえって危険な状況を生み出す可能性がある。もしあなたが今もSHA-256、SHA-512、MD5といったハッシュ関数をパスワード保存に使っているなら、それはユーザーのセキュリティを危険に晒していることに他ならない。

一体なぜ、広く使われてきたハッシュ関数が問題なのだろうか。SHA-256やMD5のような一般的なハッシュアルゴリズムは、元々データの完全性を確認したり、デジタル署名に使われたりすることを目的として設計されている。そのため、非常に高速で効率的に動作するよう作られているのだ。しかし、この「高速性」こそが、パスワード保存においては致命的な弱点となる。

具体的にその問題点を挙げよう。まず、速度が攻撃者の有利に働くという点だ。グラフィックボード(GPU)や特定用途向け集積回路(ASIC)といった特殊なハードウェアを使うと、攻撃者は1秒間に何十億ものSHA-256ハッシュを計算できてしまう。次に、並列処理の容易さがある。攻撃者は何百万ものパスワードの推測作業を同時に、つまり並列で実行できる。これにより、非常に短時間で大量のパスワードを試すことが可能になる。そして、これらの一般的なハッシュ関数には、パスワードセキュリティのための特別な保護機能が組み込まれていない。例えば、パスワードごとに異なる値を追加する「ソルト」の強制、計算を意図的に遅らせる「イテレーション回数」、あるいは大量のメモリ(RAM)を消費させる「メモリハードネス」といった仕組みがないのだ。

これらの問題が意味するのは、もしあなたのサービスからユーザーデータベースが漏洩してしまった場合、そこに保存されているハッシュ化されたパスワードは、ブルートフォース攻撃(総当たり攻撃)に対してほとんど抵抗力を持たないということだ。攻撃者は漏洩したハッシュ値を使って、驚くべき速さで元のパスワードを特定してしまうだろう。

そこで登場するのが、KDF(Key Derivation Function:鍵導出関数)だ。KDFは、安全なパスワード保存のために特別に設計された関数であり、一般的なハッシュ関数とは異なり、速度よりも防御に重点を置いている。KDFには、パスワードの安全性を劇的に高めるための重要な特性がいくつかある。

一つ目は「ユニークなソルト」だ。KDFはパスワードをハッシュ化する際、それぞれのパスワードに対してランダムでユニークな値を生成し、それをパスワードと組み合わせてハッシュ化する。これにより、たとえ同じパスワードを複数のユーザーが使っていたとしても、データベースにはそれぞれ異なるハッシュ値が保存されることになる。これは「レインボーテーブル攻撃」という、事前に計算されたハッシュ値のリストを使った攻撃を防ぐのに非常に有効だ。

二つ目は「ワークファクタ」または「イテレーション回数」だ。KDFは、パスワードのハッシュ計算を意図的に何度も繰り返したり、複雑な処理を加えたりすることで、一つ一つのパスワード推測にかかる時間を遅くする。これにより、攻撃者がブルートフォース攻撃を試みても、膨大な時間がかかり、攻撃のコストを大幅に引き上げることができる。

三つ目は「メモリハードネス」だ。Argon2やscryptといったKDFは、ハッシュ計算を行う際に大量のメモリ(RAM)を消費するように設計されている。これは、GPUやASICといった、高速計算には優れるものの搭載メモリが限られているハードウェアを使った攻撃の効率を著しく低下させる効果がある。攻撃者は高価で大量のメモリを搭載したシステムを用意しなければならず、攻撃の敷居が非常に高くなる。

では、具体的にどのKDFを使えば良いのだろうか。セキュリティの専門機関であるOWASP(Open Web Application Security Project)のパスワード保存チートシートや、NIST(米国標準技術研究所)のデジタルIDガイドラインでは、いくつかの推奨アルゴリズムが挙げられている。

その筆頭が「Argon2id」だ。これはPassword Hashing Competitionの勝者であり、メモリハードネスを持ち、さらにサイドチャネル攻撃(システムの動作を監視して情報を盗む攻撃)にも耐性がある。次に実績のある「bcrypt」は、広く使われており信頼性が高いが、メモリハードネスは持たない。また、「scrypt」もメモリハードネスを持つが、Argon2ほど普及はしていない。最後に「PBKDF2 (with HMAC-SHA256)」も、非常に高いイテレーション回数で設定すれば許容されるが、Argon2やbcryptに比べると強度は劣るとされている。

これらのKDFを使用する際には、適切なパラメータ設定が極めて重要だ。例えば、Argon2idであればメモリコスト、タイムコスト、並列度を、bcryptであればコストファクタを、scryptであればN、r、pといったパラメータを調整する。一般的には、あなたのサーバー環境で一つのパスワードのハッシュ計算に約100ミリ秒から300ミリ秒程度の時間がかかるように設定することが推奨されている。これにより、通常のログイン体験を損なうことなく、攻撃に対する十分な遅延効果を持たせることが可能になる。

実際にKDFをシステムに組み込む際の基本的な流れを見てみよう。Node.jsでArgon2idを使う例では、まずパスワードをハッシュ化する際に、argon2.hash()という関数を使い、その際にメモリコストやタイムコストといったパラメータを指定する。この関数が返すハッシュ値は、アルゴリズムの種類、使われたパラメータ、生成されたソルト、そして最終的なハッシュ値の全てを含んだ形式で保存される。これにより、将来的にアルゴリズムやパラメータが変更されても、過去のハッシュ値と互換性を保ちながら検証できる「将来性」が確保される。そして、ユーザーがログインを試みる際には、入力されたパスワードと保存しておいたハッシュ値を使ってargon2.verify()関数で検証するだけで良い。

パスワードセキュリティを万全にするためには、KDFの導入だけでなく、いくつかのベストプラクティスを組み合わせることが求められる。まず、当然のことながら、SHA-256のような単純なハッシュ関数をパスワードに使うことは絶対に避けるべきだ。そして、パスワードごとに必ずユニークな暗号学的ソルトを使用する。また、前述したように、ハッシュ値と一緒にアルゴリズムとパラメータを保存し、将来のマイグレーションやアップグレードに備える。サーバーの負荷状況に合わせて適切なハッシュ計算時間をベンチマークし、調整することも欠かせない。さらに、セキュリティ技術の進化に合わせて、定期的にパスワードを再ハッシュし直したり、より強力なアルゴリズムやパラメータに更新したりする運用も重要だ。KDFだけでなく、通信を暗号化するHTTPSの利用、一定回数以上のログイン失敗でアカウントをロックアウトする機能、二段階認証(2FA)の導入、そしてサーバー側で別途保管される「ペッパー」といった多層的な防御策を組み合わせることで、より強固なセキュリティ体制を築くことができる。

パスワードのセキュリティは、単に平文保存を避けるだけの問題ではない。現代の巧妙なクラッキング技術に対して、いかに抵抗できるかが問われている。SHA-256などのハッシュ関数ではもはや不十分であり、Argon2id、bcrypt、scryptといったKDFこそが、その防御のために特別に作られたツールであることを理解すべきだ。OWASPやNISTといった専門機関も明確にこれらのKDFの使用を推奨している。もしあなたが今もパスワードのハッシュ化だけで満足しているなら、それは過去の方法に囚われている状態だ。ユーザーとそのデータの安全を守るため、今こそKDFへの移行を真剣に考える時期が来ている。

関連コンテンツ

関連IT用語

関連ITニュース