【入門編】 サイドチャネル攻撃(タイミング攻撃)による認証バイパス – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

「0.1秒の差」が命取り?タイミング攻撃で学ぶ、パスワード比較の落とし穴

こんにちは!セキュリティの世界へようこそ。
今日は、少しマニアックですが、非常に重要な「タイミング攻撃」というハッキング手法についてお話しします。「えっ、ハッキング?」と身構える必要はありません。まずは、私たちの身近な「家の鍵」を例にして、なぜプログラムがパスワードをチェックする時に「時間」を気にする必要があるのか、一緒に紐解いていきましょう。

1. 泥棒は「音」を聞いている?

想像してみてください。あなたは玄関の鍵を開けています。この鍵は少し特殊で、正しい鍵を差し込んで回すと「カチッ」と音がしますが、間違った鍵だと「ガリッ」という重い音がします。

もしあなたが泥棒だとしたらどうしますか?
何百種類もの鍵を試すとき、「ガリッ(失敗)」と鳴るまでの時間や音の違いを観察すれば、「あ、今の鍵は形が少し惜しかったな」とか「これは全く見当違いだ」ということが分かってしまいますよね。

プログラムの世界での「タイミング攻撃」もこれと同じです。
システムがパスワードをチェックする時、もし「1文字目が違うとすぐにエラーを返す」「3文字目まで合っていると少しだけ処理に時間がかかる」といった挙動をしていたらどうなるでしょう。攻撃者はその「わずかな応答時間の差」をストップウォッチで計るように計測し、1文字ずつ正解を導き出してしまうのです。

2. なぜ「==」で比較してはいけないのか

多くの初心者エンジニアが最初に書いてしまう、よくあるコードを見てみましょう。

// 危険な比較の例
if ($input_password == $saved_password) {
    // ログイン成功!
}

この == という演算子は、プログラムにとって非常に効率的です。なぜなら、「違う文字が見つかった瞬間に、即座に比較を終了する」からです。

  • 1文字目が違えば:即終了(0.001秒)
  • 1文字目が合っているけど2文字目が違う:少しだけ計算して終了(0.002秒)

この「0.001秒の差」が、ネットワーク越しの何万回もの試行によって積み重なると、攻撃者には「あ、1文字目は『A』で合ってるな」とバレてしまうのです。これがタイミング攻撃の正体です。

3. 「定数時間比較」という魔法の盾

では、どうすればいいのでしょうか?
答えは簡単。「パスワードが合っていようが間違っていようが、常に同じ時間だけかけて比較する」のです。これを「定数時間比較(Constant-time comparison)」と呼びます。

「答えが分かっていても、最後までちゃんと全部計算してから結果を返す」という、非常に誠実(?)なやり方です。これなら、攻撃者がいくら時間を計っても、常に一定の結果しか返ってこないので、情報のヒントを一切与えません。

PHPで実装する場合、以下のように書くのが正解です。

// 安全な比較:hash_equalsを使う
// 常に一定の時間をかけて比較するため、時間の差で推測されることがありません
if (hash_equals($saved_password, $input_password)) {
    // ログイン成功!
} else {
    // ログイン失敗
}

この hash_equals という関数は、まさにこの「定数時間比較」をやってくれるセキュリティの味方です。自分でループを書いて比較しようとせず、必ず言語が用意しているこうした専用関数を使いましょう。

4. 今日からできるセキュリティの習慣

IT担当者や開発者の皆さんが、今日から現場で意識できるポイントをまとめました。

  • 「失敗した理由」を詳しく教えない:

ログイン画面で「ユーザー名が違います」や「パスワードが違います」と細かく出し分けるのは、実は攻撃者にヒントを与えています。「ログインに失敗しました」とだけ返すのが鉄則です。

  • 専用の関数を信頼する:

パスワードやAPIトークンの比較には、必ずその言語で「Constant-time」と書かれた比較関数(PHPなら hash_equals、Node.jsなら crypto.timingSafeEqual など)を選んでください。

  • ライブラリを活用する:

認証処理をゼロから自作するのは非常に危険です。信頼できる認証ライブラリやフレームワークの標準機能を使うことが、最も安全で近道な対策になります。

最後に

「たかが0.001秒」と思うかもしれません。しかし、セキュリティの世界では、そのわずかな「隙(すき)」が大きなインシデントの入り口になります。

完璧な防御を目指すのは大変ですが、まずは「比較するときは時間を一定にする」というルールを覚えるだけで、あなたの書くコードはぐっと堅牢になります。一歩ずつ、安全な開発者への道を歩んでいきましょうね!

何か分からないことがあれば、いつでもまた聞きに来てください。応援しています!

コメント

タイトルとURLをコピーしました