こんにちは!開発現場のセキュリティを守るホワイトハッカーの視点から、今回はWebアプリケーション開発で避けて通れない「パスワードの安全な保存方法」についてお話ししますね。
セキュリティに初めて触れる新人エンジニアの方や、「なんとなくハッシュ化しているけれど、これで本当に大丈夫なのかな?」と不安に思っている開発者の方に向けて、難しい数式は一切抜きで、身近な防犯の例えを交えながら優しく紐解いていきます。
一歩ずつ、確実に安全な実装を学んでいきましょう!
—
家の鍵を防犯泥棒から守る「暗号の金庫」の仕組み
皆さんは、自分の家や部屋の鍵をどのように管理していますか? 鍵をそのままオフィスの机の上に置いておいたり、「1234」のような誰でも当てられる暗証番号にしたりはしませんよね。
Webサービスにおける「パスワード」もこれと全く同じです。
ユーザーが登録したパスワードを、もしデータベース(DB)にそのままの文字(平文)で保存していたとしたらどうなるでしょうか? もし悪意ある攻撃者にDBを盗み見られてしまったら、ユーザーの全アカウントが瞬時に乗っ取りの被害に遭ってしまいます。これは、玄関の鍵を開けっぱなしにして泥棒を招き入れているようなものです。
だからこそ、パスワードはそのまま保存せず、「ハッシュ関数」という不可逆(元に戻せない)な変換機を使って、めちゃくちゃな文字列(ハッシュ値)に変換して保存します。
「レインボーテーブル」というずる賢い泥棒の存在
「じゃあ、パスワードをハッシュ化して金庫にしまえば完璧だね!」と思った方、ちょっと待ってください。実は、サイバー攻撃者は非常に頭が良いのです。
攻撃者たちは、よく使われるパスワード(passwordや123456など)をあらかじめハッシュ値に変換した「辞書(レインボーテーブル)」を持っています。泥棒が金庫の中身(ハッシュ値)を見たときに、「あ、この文字列は、辞書にある『password』を変換したやつだ!」と、一瞬で元のパスワードを見破られてしまうのです。
この泥棒のズルい技を防ぐために登場するのが、「ソルト(Salt)」と「ストレッチング(PBKDF2)」という2つの強力な防衛テクニックです。
—
PBKDF2と「反復回数(Iteration Count)」の正体
パスワードを安全に保存するためのアルゴリズムの一つに、PBKDF2(Password-Based Key Derivation Function 2)があります。名前は少し難しそうですが、やっていることはとてもシンプルです。
PBKDF2の心臓部にあるのが、「反復回数(Iteration Count)」という設定値です。これは、パスワードのハッシュ化(複雑な計算)を「何回ループさせるか」を指定するパラメータになります。
家の鍵の「合鍵職人」に例えてみよう
反復回数がどういうものか、次のような例えで考えてみましょう。
- 反復回数が「1回」の場合:
泥棒があなたの家の鍵をピッキングするのに、職人がたった1回ヤスリを削るだけで合鍵を作れてしまいます。これでは一瞬で突破されてしまいますよね。
- 反復回数を「数十万回」にする場合:
職人が同じ合鍵を作るために、気の遠くなるような数(例えば60万回以上!)ヤスリをゴシゴシと削り続けなければならないルールを作ります。
ここで疑問が湧くはずです。「そんなに何回も計算させたら、サーバーが重くなったり、ユーザーがログインするときに何分も待たされたりするんじゃないの?」と。
まさにその通り! ここがセキュリティの面白い(そして悩ましい)バランスポイントです。
- ユーザー(正当な人): ログインする時は1回しかパスワードを入力しないので、サーバー側での計算は「1回分」だけ。そのため、人間が体感する待ち時間はほんのコンマ数秒(0.1秒未満)でスムーズにログインできます。
- 攻撃者(泥棒): ユーザーのパスワードが分からないため、何百万通りものパスワードをしらみつぶしに試す(総当たり攻撃)必要があります。そのため、1回試すたびに膨大な計算(何十万回ものループ)を強いられ、コンピュータのCPUパワーがガリガリと削られて、攻撃に何十年もかかるようになるのです。
つまり、「私たち(正当なユーザー)にとっては一瞬だけど、泥棒にとっては発狂しそうなくらい面倒で時間がかかる処理」を作り出すのが、PBKDF2の反復回数というわけです。
—
【重要】いま私たちが設定すべきOWASP推奨値
セキュリティの基準は、時代の技術の進化(コンピュータの処理能力の向上)とともに厳しくなっていきます。昔は「数千回」で十分だった反復回数も、今やスーパーコンピュータや高性能なGPU(グラフィックボード)を持つ攻撃者の前では紙屑同然になってしまいます。
国際的なWebセキュリティの権威であるOWASP(Open Worldwide Application Security Project)が現在推奨している、PBKDF2の反復回数の目安は以下の通りです。
- ハッシュアルゴリズム:
SHA-256またはSHA-512 - PBKDF2の推奨反復回数:
- PBKDF2-HMAC-SHA256: 最低 600,000回 以上
- PBKDF2-HMAC-SHA512: 最低 210,000回 以上
(※2023〜2024年現在の基準値です。ハードウェアの進化スピードに合わせて、この数値は数年ごとに引き上げられていきます)
システムを設計する際は、古い解説サイトの「10,000回」といった古い数値をそのままコピーせず、必ず最新のOWASP Cheat Sheetを確認するように心がけましょう!
—
実装サンプルコード(PHPによる安全なパスワードハッシュ化)
それでは、実際の開発現場でどのようにこの設定を行うのか、PHPのコードを例に見てみましょう。PHPの標準関数である password_hash() は、内部で安全なアルゴリズム(BcryptやArgon2i/2id、あるいはPBKDF2など)をよしなに調整してくれますが、今回はPBKDF2の仕組みをイメージしやすいよう、hash_pbkdf2() を使った実装例をご紹介します。
<?php
/**
* PBKDF2を用いた安全なパスワードハッシュ化のサンプルコード
*
* 担当:新米エンジニアの皆さんへ
* このコードは、パスワードをDBに保存する際の手順を再現したものです。
*/
// 1. ユーザーが入力したパスワード(実際にはフォームから受け取る)
$plainPassword = "User_Secure_Password_123!";
// 2. ソルト(Salt)の生成
// 毎回ランダムな16バイトの文字列を生成し、パスワードごとに違う「味付け」をします。
// これにより、同じパスワードを使っているユーザーがいても、ハッシュ値が完全に別物になります。
$salt = random_bytes(16);
// 3. PBKDF2のパラメータ設定(OWASP推奨値を意識!)
$algorithm = 'sha256'; // 使用するハッシュアルゴリズム
$iterations = 600000; // 【重要】OWASP推奨の反復回数(60万回)
$length = 32; // 生成するキーの長さ(バイト数)
// 4. ハッシュ化の実行(ここでコンピュータに重い計算をあえてさせます)
$hash = hash_pbkdf2(
$algorithm,
$plainPassword,
$salt,
$iterations,
$length,
false // trueにするとバイナリ出力、falseにすると16進数の文字列出力
);
// 5. データベースに保存するデータ構造のイメージ
// ソルトと反復回数、そして生成されたハッシュ値をセットで保存しないと、後でログイン検証ができなくなります!
$storedData = [
'salt' => bin2hex($salt), // DBには文字列として保存するため16進数化
'iterations' => $iterations, // 何回ループさせたかの記録
'hash' => $hash // 最終的なハッシュ値
];
// デバッグ用出力(実際の開発ではパスワードやハッシュを画面に直接出力しないよう注意!)
echo "--- パスワード安全保存のデバッグ ---\n";
echo "ソルト: " . $storedData['salt'] . "\n";
echo "反復回数: " . $storedData['iterations'] . "回\n";
echo "生成されたハッシュ値: " . $storedData['hash'] . "\n";
?>
実装時の大切なポイント
- ソルトは使い回さない: ユーザーごとに必ずランダムな
random_bytes()を生成して保存してください。同じソルトを全員で使い回すと、ソルトの意味がなくなってしまいます。 - 反復回数を記録しておく: ログイン時にパスワードを検証する際、「このユーザーは何回ループさせて作ったハッシュだっけ?」となるため、反復回数やアルゴリズムの種類も一緒にDB(または設定ファイル)で管理しておく必要があります。
—
まとめ:これからのセキュリティ設計に向けて
今回は、PBKDF2の反復回数とOWASP推奨値について、防犯の例えを交えながら解説しました。
- パスワードはそのまま保存せず、ハッシュ化して金庫にしまう。
- レインボーテーブル対策として、ランダムな「ソルト」を混ぜる。
- 総当たり攻撃(力づくの解読)を防ぐために、PBKDF2の「反復回数」をOWASP推奨値(SHA-256なら60万回以上)に設定して、泥棒の計算コストを跳ね上げる。
セキュリティ対策は、「一度作ったら終わり」ではなく、時代の変化に合わせて少しずつ基準をアップデートしていく泥臭い作業でもあります。しかし、こうした基本の仕組みをしっかりと理解してコードを書くことで、あなたの開発するWebアプリケーションは、何万人ものユーザーの大切な情報を守る「堅牢な要塞」へと生まれ変わります。
一歩ずつ、確実に安全なエンジニアへの階段を登っていきましょう!次回のセキュリティ解説もお楽しみに!
コメント