パスワードは「保存」されていない
まともな Web サービスは、あなたのパスワードをそのまま保存していません。保存されているのは、パスワードを一方向関数 (ハッシュ関数) に通して生成された「ハッシュ値」です。ハッシュ値からは元のパスワードを復元できません。
ログイン時、サーバーは入力されたパスワードをハッシュ化し、保存済みのハッシュ値と比較します。一致すれば認証成功。パスワードそのものは、一瞬たりともサーバーのストレージに記録されません。
では、なぜこんな回りくどいことをするのか。それは、データベースが漏洩したときの被害を最小化するためです。
平文保存の恐怖 - 実際に起きた事件
パスワードを平文 (そのままの文字列) で保存していた企業がデータ漏洩を起こすと、全ユーザーのパスワードが即座に攻撃者の手に渡ります。
- Adobe (2013 年): 1 億 5,300 万件のアカウント情報が漏洩。パスワードは暗号化されていたが、ハッシュ化ではなく可逆暗号 (3DES-ECB) で保存されていたため、同じパスワードは同じ暗号文になり、頻度分析で大量のパスワードが解読された
- RockYou (2009 年): 3,200 万件のパスワードが平文で漏洩。このデータは今でもパスワードクラッキングの辞書として広く使われている
- Facebook (2019 年): 数億件のパスワードが社内システムに平文でログされていたことが発覚。外部漏洩はなかったが、社内の誰でも閲覧可能な状態だった
ハッシュ化されていれば、データベースが漏洩しても攻撃者が得るのはハッシュ値だけです。元のパスワードを知るには、ハッシュ値を「逆算」する必要がありますが、適切なハッシュ関数を使っていれば、これは計算量的に非現実的です。
ハッシュ関数の進化 - MD5 から bcrypt へ
MD5 と SHA-1 - 速すぎて危険
初期のパスワードハッシュには MD5 や SHA-1 が使われていました。しかし、これらは「高速に計算できる」ことが設計目標であり、パスワードハッシュには逆に不向きです。最新の GPU は 1 秒間に数十億回の MD5 ハッシュを計算でき、短いパスワードなら総当たりで数秒で解読できます。
ソルト - 同じパスワードでも異なるハッシュに
ソルト (salt) は、パスワードをハッシュ化する前に付加するランダムな文字列です。同じパスワード「password123」でも、ユーザーごとに異なるソルトが付加されるため、ハッシュ値はすべて異なります。これにより、事前計算済みのハッシュテーブル (レインボーテーブル) による攻撃を無効化できます。
bcrypt - 意図的に遅いハッシュ関数
bcrypt (1999 年) は、パスワードハッシュ専用に設計された関数です。最大の特徴は「意図的に遅い」ことです。コストファクター (work factor) というパラメータで計算量を調整でき、ハードウェアの性能向上に合わせて計算コストを引き上げられます。
bcrypt のハッシュ 1 回の計算に 100 ms かかるように設定すれば、正規のログイン (1 回の計算) にはほとんど影響しませんが、総当たり攻撃 (数十億回の計算) は事実上不可能になります。
Argon2 - 現在の最先端
Argon2 は 2015 年の Password Hashing Competition で優勝したアルゴリズムで、計算時間だけでなくメモリ使用量も調整できます。GPU による並列攻撃に対して、bcrypt よりも高い耐性を持ちます。
「パスワードを忘れた」で元のパスワードが送られてきたら危険信号
パスワードリセット時に、元のパスワードがメールで送られてくるサービスがあったら、そのサービスはパスワードを平文 (または可逆暗号) で保存しています。ハッシュ化されていれば、元のパスワードを復元することは不可能だからです。
正しい実装では、パスワードリセットは「新しいパスワードを設定する」フローになります。元のパスワードを教えてくれるサービスは、セキュリティの基本を理解していない証拠です。
まとめ
パスワードのハッシュ化は、「データベースは漏洩する」という前提に立った防御策です。MD5 の時代から bcrypt、Argon2 へと進化してきたハッシュ関数は、攻撃者の計算能力の向上に対抗し続けています。
ユーザーとしてできることは、サービスごとに異なる強力なパスワードを使い、二要素認証を有効にし、可能であればパスキーに移行することです。IP 確認さんで自分のネットワーク情報を確認するように、自分のパスワード管理の状態も定期的に見直してください。
暗号化とハッシュの仕組みを体系的に学びたい方には、暗号技術の入門書が参考になります。