【実務・中級編】 サイドチャネル攻撃:タイミング攻撃による秘密鍵の抽出 – 暗号理論・認証基盤 & エンドポイントセキュリティ防御ガイド

現場のエンジニア諸君、お疲れ様。今日もどこかのサーバーで脆弱性が突かれ、深夜のインシデント対応に追われていないことを祈るよ。

今日は「暗号」という強固な城壁に潜む、極めて静かな侵入経路について話そう。教科書では「AESやRSAは安全である」と教わるが、現実は甘くない。アルゴリズムそのものが破られなくても、「処理にかかる時間」を計測されるだけで、秘密鍵はガラスケースに入れた宝物のように丸見えになるんだ。

これが「タイミング攻撃(Timing Attack)」だ。

1. なぜ「速いコード」が脆弱性を生むのか

想像してほしい。パスワードの照合やデジタル署名の計算を行うとき、コード内でこんな処理を書いていないか?

# 脆弱な比較関数の例(絶対にやめろ)
def check_signature(user_sig, secret_sig):
    for i in range(len(secret_sig)):
        if user_sig[i] != secret_sig[i]:
            return False  # ここで即座に処理が終了する
    return True

このコードは、一見効率的だ。不一致を見つけた瞬間にループを抜ける。だが、攻撃者はこの「処理時間の差」をミリ秒単位で計測する。
「先頭の1文字が合っているとき」と「間違っているとき」で、わずか数ナノ秒の差が生じる。この差を何万回と統計的に分析すれば、秘密鍵の各ビットを1つずつ特定できてしまう。これがタイミング攻撃の恐ろしさだ。

2. 実践:タイミング攻撃を無効化する「定数時間実装」

この攻撃を防ぐ唯一の解は、「入力が何であれ、必ず同じ時間で処理を終える」ことだ。これを「定数時間(Constant-time)アルゴリズム」と呼ぶ。

Pythonであれば、標準ライブラリの hmac.compare_digest を使うのが鉄則だ。自分でループを書いて比較してはいけない。

Pythonによるセキュアな比較例

import hmac

def verify_token(user_input, secret_token):
    # hmac.compare_digestは、内容に関わらず常に一定の時間で比較を行う
    # これによりタイミング攻撃の余地を排除する
    return hmac.compare_digest(user_input, secret_token)

PHPの場合も同様だ。== 演算子による文字列比較は、先頭から一致を確認するためタイミング攻撃に弱い。必ず hash_equals を使え。

PHPによるセキュアな比較例

<?php
// ユーザーからの入力とDBのハッシュを比較する際
$user_hash = $_POST['api_key'];
$stored_hash = get_stored_key(); // DBから取得した鍵

// '===' ではなく 'hash_equals' を使用すること
if (hash_equals($stored_hash, $user_hash)) {
    // 認証成功
} else {
    // 認証失敗
}
?>

3. Webアプリ開発者が陥る「盲点」

APIの認証や署名チェックだけでなく、暗号ライブラリの選定にも注意が必要だ。

  • RSA実装の罠: RSAのべき乗演算において、処理時間を隠蔽するマスキング(Blinding)処理が行われていない古いライブラリは、秘密鍵抽出のリスクが高い。OpenSSLなどの枯れたライブラリを使い、必ず最新版にアップデートしておくこと。
  • JavaScriptでの暗号化: ブラウザ側で暗号処理を行う場合、Web Crypto API を使え。これはブラウザが低レイヤーで定数時間処理を保証するように設計されている。crypto.subtle を利用するのがプロの選択だ。

Web Crypto APIの利用例 (JavaScript)

async function verifySignature(key, signature, data) {
    // Web Crypto APIは内部的にサイドチャネル攻撃対策が施されている
    const isValid = await crypto.subtle.verify(
        "RSASSA-PKCS1-v1_5",
        key,
        signature,
        data
    );
    return isValid;
}

4. セキュリティチーフからの「現場の心得」

最後に、インフラ設計者・開発リーダーとしてこれだけは肝に銘じてほしい。

1. 自作暗号の実装禁止: 暗号学の専門家が何十年もかけて磨き上げたライブラリ以外、決して自分で暗号アルゴリズムを実装するな。特に「最適化」という名目でループをいじり始めると、ほぼ確実に脆弱性が生まれる。
2. ログと監視: 異常なリクエスト回数や、極端にレスポンス速度を計測しようとする動きをWAFやIDSで監視せよ。タイミング攻撃は短時間で何万回も試行する必要があるため、異常なアクセスパターンを検知できるはずだ。
3. ライブラリの選定基準: ライブラリを選定する際は、GitHubのスター数だけでなく、「Constant-time implementation」が謳われているかをドキュメントで確認する癖をつけろ。

セキュリティとは、完璧な製品を一つ置くことではない。「綻び(ほころび)を生ませない泥臭い実装の積み重ね」こそが、強固な防御の正体だ。

コードを書くとき、ふと立ち止まって考えてみてほしい。「この比較処理、攻撃者に時間を測られても胸を張れるか?」と。その自問自答が、君たちのプロダクトを救うことになる。

また現場で会おう。健闘を祈る。

コメント

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