なぜ、あなたのパスワード管理は「2010年代」のままなのか?
現場でコードレビューをしていると、未だに「SHA-256でハッシュ化しています」という設計に遭遇する。正直に言おう。その設計は、今の攻撃者からすれば「どうぞパスワードを盗んでください」と言っているようなものだ。
GPUやASICが数秒で何十億通りのハッシュを計算する現代において、単なるSHA-256は「ストレッチング」すらしていないに等しい。今日は、XSSのような脆弱性で万が一データベースが流出したとしても、攻撃者に「絶望」を与えるためのパスワードハッシュの最適解、Argon2idについて深掘りしていく。
—
1. なぜSHA-256ではダメなのか?(攻撃者の視点)
SHA-256は「高速」だ。これがパスワード保存において最大の致命傷になる。
攻撃者はDBを盗み出した後、オフライン環境で総当たり攻撃(ブルートフォース)を仕掛ける。SHA-256の場合、最新のGPUなら1秒間に数億回以上のハッシュ計算が可能だ。つまり、単純なパスワードであれば数分で平文に復元される。
対して、Argon2idは「メモリ硬度(Memory Hardness)」という概念を持っている。計算に大量のRAMを消費させることで、GPUでの並列処理を物理的に困難にする。これこそが、現代のパスワードストレージにおける「防御の砦」だ。
—
2. 実装の正解:Argon2idを使う(PHP編)
PHPには標準で強力なハッシュ関数が組み込まれている。わざわざ独自のライブラリを入れる必要はない。password_hash() を使え。
65536, // 64MBを消費させる
‘time_cost’ => 4, // 4回反復
‘threads’ => 2, // 2スレッド使用
];
$hash = password_hash($password, PASSWORD_ARGON2ID, $options);
// ログイン時の照合
if (password_verify($password, $hash)) {
echo “認証成功。セッションを発行します。”;
} else {
echo “認証失敗。”;
}
?>
運用上のポイント
- ソルトは自動生成:
password_hash()は内部で安全なソルトを自動生成し、ハッシュ値に埋め込む。自分でソルトを管理しようとしてバグを生むのは、アマチュアのやり方だ。 - コストパラメータの調整: サーバーのスペックに合わせて
memory_costを調整せよ。認証に0.5秒〜1秒かかる程度が、ユーザー体験を損なわず、攻撃を極限まで遅延させるスイートスポットだ。
—
3. XSSとパスワードの「最悪な関係」
「パスワードを正しくハッシュ化していればXSSは怖くない」と思っているなら、それは大きな勘違いだ。
XSS(クロスサイトスクリプティング)は、攻撃者がブラウザ上でスクリプトを動かす脆弱性だ。
- 反射型: 検索窓などに悪意あるスクリプトを仕込み、URLをクリックさせる。
- 格納型: 掲示板等にスクリプトを書き込み、閲覧した全ユーザーのクッキーを盗む。
- DOM型: サーバーを介さず、JSの実行フローを悪用する。
XSSでパスワードそのものを盗むことは難しいが、「管理者権限のセッションハイジャック」は容易だ。管理者としてログインさせられれば、DBのダンプを取得される。つまり、ハッシュ化がどれほど堅牢でも、XSSは「門番」を無力化する。
XSSを「コードレベル」で防ぐ:Content Security Policy (CSP)
アプリケーションコードでのエスケープ(htmlspecialcharsなど)は当然の義務だが、多層防御としてCSPを導入せよ。Nginxのレスポンスヘッダーに以下を追加するだけで、攻撃者のスクリプト実行を劇的に制限できる。
Nginx設定例: CSPヘッダーでインラインスクリプトを禁止
add_header Content-Security-Policy “default-src ‘self’; script-src ‘self’; object-src ‘none’;”;
これだけで、「見知らぬドメインからのスクリプト読み込み」や「インラインスクリプトの実行」がブロックされる。XSSのPoCを試しても、ブラウザのコンソールで軒並みエラーが出るはずだ。
—
4. 最後に:プロのセキュリティエンジニアからの助言
技術は常に進化する。今日書いたArgon2idも、5年後にはさらに強固なアルゴリズムに取って代わられているかもしれない。
だが、エンジニアが守るべき本質は変わらない。
1. 「自分で暗号アルゴリズムを作らない」: 枯れた、かつ標準的なライブラリを使え。
2. 「防御は多層で考える」: ハッシュ化が完璧でも、XSSを放置するな。入力値検証を怠るな。
3. 「疑うこと」: 自分のコードが「今日、脆弱性が見つかったらどうなるか?」を常に自問自答せよ。
インシデントは教科書通りには発生しない。現場の泥臭い戦いは、あなたの書いたコードの品質にかかっている。明日からの実装で、その「パスワードの扱い」を見直してほしい。それが我々の責務だ。
コメント