こんにちは!ITインフラやアプリ開発の世界へようこそ。新人エンジニアの皆さん、日々の業務でお疲れ様です。
セキュリティの勉強をしていると、「ハッシュ関数」や「SHA-2」といった言葉によく出会いますよね。「パスワードを安全に保存するためのもの」「データを改ざんから守るもの」と教わった方も多いのではないでしょうか。
でも、ちょっと待ってください。「安全だ」と信じ込んでいるその仕組みの裏側で、実は巧妙な罠が仕掛けられているとしたら……?
今回は、SHA-2などの代表的なハッシュ関数が持つ「ある秘密の弱点」、そしてそれを狙う「長さ拡張攻撃(Length Extension Attack)」というちょっとドキッとするハッシュの攻撃手法について、身近な例えを交えながら優しく紐解いていきたいと思います。一歩ずつ、安心して学んでいきましょう!
—
1. 家の鍵で例える「ハッシュ関数」と「MAC」の仕組み
まずは、ハッシュ関数がどんなものかを簡単に復習しておきましょう。
ハッシュ関数とは、どんな長さのデータを入れても、決まった長さのバラバラに見える文字列(ハッシュ値)に変換してくれるマジックボックスのようなものです。特徴的なのは、「元のデータからハッシュ値を作るのは簡単だけど、ハッシュ値から元のデータを逆算するのは極めて難しい(一方向性)」ということ。
ここで、よくあるセキュリティの勘違いを見てみましょう。
「データの改ざんを防ぐために、データの後ろに秘密の合言葉(シークレットキー)をくっつけて、一緒にハッシュ化しちゃえば安全だよね?」
これを、身近な例えで考えてみます。
- データ: 荷物の段ボール箱
- 秘密の合言葉: あなたと家族だけが知っている「合い言葉のスタンプ」
- やりたいこと: 届いた荷物が途中で中身をすり替えられていないか確認したい
あなたは段ボール箱のフタに、合言葉のスタンプをペタッと押して発送しました。受け取った人は、同じ合言葉のスタンプを持っているので、届いた箱のスタンプを見て「うん、中身は改ざんされていないな!」と確認できます。
……一見、完璧に見えますよね?
しかし、ここに「長さ拡張攻撃」という泥棒のテクニックが入り込む隙があるのです。
—
2. 泥棒のテクニック「長さ拡張攻撃」の正体
Merkle-Damgard(マークル・ダームガルド)構造という、SHA-2などで使われている伝統的なハッシュ関数の仕組みには、ちょっとした「おせっかいな癖」があります。
それは、「データの末尾にデータを付け足して計算を続けることができる」という性質です。
先ほどの段ボール箱の例で考えてみましょう。
泥棒(攻撃者)は、あなたが送った段ボール箱を途中でこっそり手に入れました。泥棒はあなたの「合言葉」そのものは知りません。しかし、箱に押されたスタンプ(ハッシュ値)と、箱のサイズ(データの長さ)は見ることができます。
ここで泥棒は、スタンプの仕組みの「おせっかいな癖」を利用して、こう考えました。
「元の箱を開けずに、その後ろ側に勝手に別の荷物を継ぎ足して、新しいスタンプを計算しちゃえばいいや!」
驚くことに、SHA-2(SHA-256など)では、元の合言葉を知らなくても、「元のハッシュ値」と「元のデータの長さ」さえ分かっていれば、その末尾にデータを付け足した状態の正しいハッシュ値を計算できてしまうのです。
結果として、受け取り側は「あれ、ちゃんと正しいスタンプが押されているぞ。中身は改ざんされていないんだな」と、泥棒が継ぎ足した悪意あるデータまで本物だと信じ込んでしまいます。これが、長さ拡張攻撃の恐ろしいメカニズムです。
—
3. 対策の基本:HMAC(Hash-based Message Authentication Code)を使おう
「うわ、じゃあSHA-2なんて怖くて使えないじゃん!」と思いましたか?
安心してください。この弱点を完全に克服するための正攻法がちゃんと用意されています。それが HMAC(エイチマック) です。
HMACは、秘密の合言葉をただ単純にデータの「後ろ」にくっつけるのではなく、ハッシュ関数を二重に組み合わせるなどして、泥棒が後ろにデータを付け足せないようにガチガチにガードする仕組みです。
実務の開発では、自分でハッシュの計算ロジックを自作するのではなく、プログラミング言語が用意してくれている標準ライブラリのHMAC機能(例: hash_hmac や Hmac クラスなど)を必ず使うようにしましょう。
PHPでのHMAC実装例
例えば、PHPでデータを安全に検証するためのHMACを使うコードは、このように非常にシンプルです。
<?php
// サーバー側だけが知っている秘密の鍵(絶対に外部に漏らしてはいけません)
$secretKey = 'super_secret_key_to_protect_data';
// ユーザーから送られてきた、または保護したいデータ
$data = 'user_id=100&role=admin';
// 【対策】単純に結合するのではなく、HMAC-SHA256を使って安全な署名(ハッシュ値)を生成する
$signature = hash_hmac('sha256', $data, $secretKey);
// 生成された署名を出力
echo "安全な署名: " . $signature . "\n";
// --- 受信側での検証イメージ ---
// 送られてきたデータと署名を、同じ秘密鍵を使って検証します
$incomingData = 'user_id=100&role=admin';
$incomingSignature = $signature; // 実際にはリクエストヘッダー等から受け取る
$calculatedSignature = hash_hmac('sha256', $incomingData, $secretKey);
// タイミング攻撃を防ぐ安全な文字列比較(hash_equals)を使用する
if (hash_equals($calculatedSignature, $incomingSignature)) {
echo "検証成功:データは改ざんされていません!\n";
} else {
echo "検証失敗:データが不正に改ざんされている可能性があります!\n";
}
?>
—
4. 次世代の選択肢:SHA-3の仕組み
「そもそも、そのMerkle-Damgard構造の癖自体をなくせないの?」
はい、その声に応えて作られたのが SHA-3 です。
SHA-3は、SHA-2とはまったく異なる「スポンジ構造(Sponge Construction)」という数学的アプローチを採用しています。データをスポンジのように吸い込み、内部でグチャグチャにかき混ぜてから出力する仕組みです。
このSHA-3ベースの関数(SHA3-256 など)や、同じくスポンジ構造を持つ SHAKE といったアルゴリズムでは、構造上、長さ拡張攻撃が原理的に発生しません。
将来的なシステム設計や、より堅牢性が求められるアーキテクチャでは、SHA-3の採用も非常に強力な選択肢となります。
—
5. まとめ:現場で迷ったらどうする?
ここまで、長さ拡張攻撃の仕組みと対策について見てきました。最後に、現場のエンジニアとしてこれだけは押さえておいてほしいポイントをまとめます。
1. 生データの末尾に秘密鍵をくっつけてハッシュ化しない
(これが長さ拡張攻撃の温床になります。絶対にやめましょう!)
2. メッセージ認証には必ず HMAC を使う
(プログラムを書くときは、必ず hmac 系関数やライブラリを選定してください)
3. 可能な限りモダンなアルゴリズム(SHA-2 + HMAC、または SHA-3)を選択する
セキュリティの世界は奥が深く、最初は難しく感じるかもしれませんが、こうして仕組みや例えを一つずつ紐解いていけば、決して恐ろしいものではありません。
「一歩ずつ、安全なコードを書けるようになっていきましょう!」
皆さんの開発するシステムが、サイバー攻撃からしっかりと守られる堅牢なものになるよう、陰ながら応援しています!
コメント