こんにちは!セキュリティチームのベテラン(と呼ばれつつ、日夜泥臭いログ解析と格闘しているエンジニア)です。
今回は、Web開発や認証基盤の裏側でこっそり、しかしものすごく重要な役割を担っている「ハッシュ関数」のお話です。特に、SHA-2からSHA-3への進化の歴史の中で解決された、ちょっと恐ろしい「長さ拡張攻撃(Length Extension Attack)」という脆弱性について、身近な例えを交えながら優しく紐解いていきたいと思います。
「難しい数学の数式はいかい、要するにどういうこと?」という新人のIT担当者や開発者の方向けに、一歩ずつ解説していきますので、ぜひコーヒーでも飲みながらリラックスして読んでくださいね。
—
1. パスワードやデータの改ざんを守る「ハッシュ関数」のおさらい
まず前提として、ハッシュ関数がどんなものかおさらいしておきましょう。
ハッシュ関数とは、どんなに長いデータ(例えば「猫の画像」や「数万文字のパスワードのリスト」など)を入力しても、決まった長さのバラバラな文字列(ハッシュ値)に変換してくれるマジックボックスのようなものです。
- 一方向性: ハッシュ値から元のデータを逆算するのは、ぐちゃぐちゃに混ぜたミキサーの中身から元の果物を完璧に復元するくらい不可能。
- 雪崩効果: 元のデータが1文字でも変わると、出力されるハッシュ値がまったく別のものに変わる。
Webアプリの世界では、データベースに生のパスワードを保存する代わりに、このハッシュ値(SHA-256など)を保存しています。ログイン時には、ユーザーが入力したパスワードをハッシュ化して、保存されている値と一致するかをチェックするわけですね。
—
2. 泥棒の新しい手口!「長さ拡張攻撃」の恐ろしいメカニズム
さて、ここからが本題です。実は、MD5やSHA-1、そして広く使われているSHA-2(SHA-256など)には、「長さ拡張攻撃(Length Extension Attack)」という構造的な弱点があります。
家の鍵の例えで考えてみましょう
想像してみてください。あなたは大切な手紙に、秘密の合い言葉を添えて封筒に入れています。
SHA-2のような古いタイプのハッシュ関数は、いわば「手紙の本文の末尾に、決まった手順で合い言葉を付け足して、まとめて封をするガムテープ」のような仕組みをしています。
ここで、悪い泥棒(攻撃者)が、あなたの封筒(ハッシュ値がついたデータ)を途中で盗み見たとします。
泥棒は、元の手紙の本文も、合い言葉が何かも知りません。しかし、SHA-2の「ガムテープの貼り方(構造)」を知っていると、こんな悪だくみができてしまいます。
1. 「元の手紙の長さ」が分かっていれば、ガムテープの端っこに勝手に新しいメッセージ(例:「全財産を私に送る」など)を付け足すことができる。
2. 計算上の継ぎ目を埋めるパディング(余白)を勝手に推測し、本文の後ろに連結させる。
3. 結果として、「元の合い言葉を知らないのに、勝手に追加メッセージを含んだ正しいハッシュ値」を偽造できてしまう!
これが長さ拡張攻撃の正体です。APIの改ざん検知などで「データ + 秘密鍵のハッシュ」という安易な実装をしていると、この攻撃によってデータを勝手に後ろに付け足されて改ざんされてしまうリスクがあります。
—
3. 救世主「SHA-3(Keccak)」とスポンジ関数の仕組み
この恐ろしい長さ拡張攻撃を根本から解決するために登場したのが、次世代の標準ハッシュ関数であるSHA-3(Keccak:ケシャック)です。
SHA-2までは、データを一定のブロックごとに順番に処理していく「マーク・ダンプガード構造」という仕組みを採用していたため、末尾へのデータ追加(拡張)に弱いという宿命がありました。
しかし、SHA-3は全く異なる「スポンジ関数(Sponge Construction)」という内部構造を採用しています。
スポンジの例えでイメージしよう
SHA-3の仕組みは、文字通り台所の「スポンジ」そっくりです。
1. 吸水(吸収フェーズ / Absorbing Phase):
入力データを、スポンジに水を吸わせるように、ゴクゴクと内部の状態(ステート)に混ぜ合わせていきます。データはスポンジ全体に染み込み、元のデータの形は完全に失われます。
2. 絞り出し(絞り出しフェーズ / Squeezing Phase):
十分に混ぜ合わせた後、今度はスポンジを「キュッと絞って」ハッシュ値を取り出します。
このスポンジ構造の何がすごいかというと、「データを途中で継ぎ足しても、吸収フェーズの最初からスポンジ全体に混ぜ直されるため、後ろから勝手にデータを付け足しても辻褄が合わなくなる(ハッシュの偽造ができない)」という点です。
構造的に長さ拡張攻撃が不可能になっているため、SHA-3を使っていれば、この脆弱性に怯える必要はなくなるというわけです。
—
4. 実務での実装:PHPでのハッシュ生成と比較
それでは、実際の開発現場でどのようにハッシュ関数を扱うべきか、PHPのコード例を交えて見ていきましょう。
一歩ずつ安全な実装に近づいていきましょうね。
以下のサンプルコードは、データを安全にハッシュ化する基本的な実装例です。
<?php
/**
* 安全なハッシュ生成・検証のサンプルコード
*
* 新人の開発者向けに、ハッシュ関数の選定と使い方を解説します。
* 古いハッシュ(MD5やSHA-1)は絶対に使わず、SHA-2(推奨: sha256)やSHA-3を利用しましょう。
*/
// ユーザーから受け取った機密データ(またはAPIのリクエストデータ)
$user_data = "user_id=123&action=transfer&amount=10000";
// 1. SHA-256を用いたハッシュ生成(広く普及しており実用的ですが、設計によっては長さ拡張攻撃に注意が必要です)
$sha256_hash = hash('sha256', $user_data);
echo "SHA-256 Hash: " . htmlspecialchars($sha256_hash, ENT_QUOTES, 'UTF-8') . "\n";
// 2. より堅牢なSHA-3(sha3-256)を用いたハッシュ生成
// SHA-3はスポンジ構造を持つため、長さ拡張攻撃への耐性があります!
if (in_array('sha3-256', hash_algos())) {
$sha3_hash = hash('sha3-256', $user_data);
echo "SHA-3 (sha3-256) Hash: " . htmlspecialchars($sha3_hash, ENT_QUOTES, 'UTF-8') . "\n";
} else {
echo "お使いのPHP環境ではsha3-256がサポートされていません。\n";
}
/**
* 【セキュリティのワンポイントアドバイス】
* パスワードを保存する際は、単純なハッシュ関数(SHA-2やSHA-3)をそのまま使うのではなく、
* 必ず「ソルト(Salt)」の付与と、PHPの password_hash() 関数(内部でbcryptやArgon2idを使用)を使いましょう!
* パスワードハッシュにSHA-3をそのまま使うのは、計算が速すぎてブルートフォース攻撃に弱いため推奨されません。
*/
コードの解説と実務での注意点
hash('sha3-256', ...)を使うことで、PHP環境でも手軽にSHA-3の恩恵を受けることができます。- 注意点として、データベースにパスワードを保存する場合は、SHA-2やSHA-3を直接使うのではなく、PHP標準の
password_hash($password, PASSWORD_DEFAULT)を使ってください。パスワード保存には「ストレッチング(計算をあえて遅くする仕組み)」が不可欠だからです。 - 今回解説した長さ拡張攻撃は、主に「APIの署名検証」や「メッセージ認証(HMACを使わない独自の検証など)」を自前で実装している場合にリスクとなります。できるだけ標準化された安全なプロトコル(JWTやHMAC-SHA256など、あるいはSHA-3のHMAC)を組み合わせるのが鉄則です。
—
5. まとめ:安全なアプリケーション開発に向けて
今回は、SHA-2の抱える長さ拡張攻撃の仕組みと、それを華麗に解決するSHA-3(スポンジ関数)の仕組みについてお伝えしました。
- 古いハッシュ関数やSHA-2の一部実装には、後ろからデータを継ぎ足して偽造される「長さ拡張攻撃」のリスクがある。
- SHA-3(Keccak)は「スポンジ関数」という独自の構造により、この攻撃を構造的に無効化している。
- 用途に合わせて適切なハッシュアルゴリズム(パスワードなら
password_hash、データ検証ならSHA-3など)を選択することが、セキュリティ事故を防ぐ第一歩。
セキュリティの世界は一見すると難解な用語が多くて尻込みしがちですが、仕組みの本質を「身近な例え」で理解してしまえば、日々のコーディングやインフラ設計で何を気をつければいいのかがグッと見えてきます。
一歩ずつ、安全で堅牢なシステムを作れるエンジニアを目指して一緒に学んでいきましょう!次回の解説もお楽しみに。
コメント