パディングオラクル攻撃の原理(CBC を1バイトずつ復号する)
鍵がなくても CBC 暗号文は復号できる。サーバーが返す「パディング検証エラー」という1ビットの漏れを梃子に、1バイトずつ平文を割り出す手順を原理から押さえ、対策まで一気通貫で理解する。
- 1.パディングが正しいか否か(1ビット)をサーバーが区別して返すだけで、攻撃者は鍵なしに CBC 暗号文を1バイトずつ復号できる。
- 2.鍵を破るのではない。前ブロックの暗号文を細工し、復号後の末尾が正しいパディングになる値を総当たりで探すと、復号途中の中間値が逆算できる仕組み。
- 3.根本対策は Encrypt-then-MAC。復号する前に MAC で改ざんを弾けばオラクルが消える。POODLE/Lucky13 もこの設計欠陥が根。
「鍵を破る」攻撃ではない
パディングオラクル攻撃は、AES や DES そのものを破りません。鍵は最後まで分からないまま、暗号文だけを復号します。突くのは暗号アルゴリズムではなく、CBC モードの構造と、サーバーが漏らす1ビットの情報です。
前提を3つ押さえます。詳しくは 暗号の基礎 を参照してください。
- ブロック暗号:AES は16バイト単位でしか処理できない。平文はブロック長の倍数に**詰め物(パディング)**して長さを合わせる。
- CBC モード:各ブロックを暗号化する前に1つ前の暗号文ブロックと XOR して連鎖させる。先頭ブロックの相手が IV(初期化ベクトル)。
- パディング検証:復号後、末尾の詰め物が規則どおりかをサーバーが点検する。ここが不正なら専用のエラーが返る――この区別が「オラクル(神託)」になる。
末尾を N バイト埋める必要があるとき、その N バイトすべてに値 N を入れます。1バイト余れば 01、3バイト余れば 03 03 03、ちょうど割り切れても1ブロック丸ごと 10(=16)を足します。復号側は「末尾バイトの値 N を読み、後ろ N バイトが全部 N か」を検証します。この検証の合否が漏れることが攻撃の入口です。
CBC 復号の式を分解する
攻撃の鍵は、CBC 復号が「ブロック暗号の復号」と「XOR」の2段だという点です。D を鍵によるブロック復号、C[i] を i 番目の暗号文ブロック、P[i] を平文ブロックとすると、
中間値 I[i] = D(C[i]) ← 鍵がないと攻撃者には不明
平文 P[i] = I[i] XOR C[i-1] ← 直前の暗号文ブロックと XOR
(先頭は C[i-1] の代わりに IV を使う)
ここで決定的に重要なのは、I[i] = D(C[i]) は C[i-1] に一切依存しないことです。攻撃者が手前のブロック C[i-1] をどう書き換えても、I[i] は同じ値のまま。すると平文側はこう動きます。
偽の手前ブロック R を送ると、復号結果の末尾は
P'[i] = I[i] XOR R
攻撃者は R を自由に選べる。I[i] は固定。
→ R を調整すれば P'[i] を狙った値に「ずらせる」
I[i] さえ分かれば、本物の平文は P[i] = I[i] XOR C[i-1](C[i-1] は既知)で即座に求まります。攻撃の目標は鍵ではなく、この中間値 I[i] を1バイトずつ手に入れることです。
末尾1バイトを当てる状態遷移
ターゲットブロック C[i] の中間値 I[i] の最後の1バイトを求めます。攻撃者は16バイトの偽ブロック R = R[0..15] を自分で作り、R || C[i] の2ブロックをサーバーに送って、パディング検証の合否だけを観測します。
- 状態A(探索開始):
R[15]を0x00から0xFFまで順に変えて送る。サーバーはR || C[i]を復号し、末尾バイトP'[15] = I[i][15] XOR R[15]を検証する。 - 状態B(合格を1つ掴む):256通りのうち、ふつう1つだけ「パディング OK」が返る。これは末尾が
01になった瞬間、つまりI[i][15] XOR R[15] = 0x01が成立したR[15]。 - 状態C(中間値を逆算):式を解いて
I[i][15] = R[15] XOR 0x01。鍵なしで中間値の1バイトが確定した。 - 状態D(本物の平文へ):
P[i][15] = I[i][15] XOR C[i-1][15]。C[i-1]は手元の暗号文なので、平文の最終バイトが読める。
末尾が 01 の他に、たまたま 02 02(後ろ2バイトが両方 02)でも検証は通ります。合格が複数出たり挙動が怪しいときは、R[14] を1ビット変えて再送します。本物の 01 一致なら末尾だけの条件なので合否は変わらず、02 02 の偶然なら崩れて不合格になります。これで真の一致を選別できます。
2バイト目以降へ繰り上げる
末尾が取れたら、狙うパディング長を1つ伸ばします。次は末尾2バイトを 02 02 にしたい。I[i][15] はもう分かっているので、末尾バイトが確実に 02 になるよう R[15] = I[i][15] XOR 0x02 に固定します。そのうえで R[14] を 0x00〜0xFF で総当たりし、末尾が 02 02 になる(=パディング OK)瞬間を探す。
手順(k バイト目を求める。pad = 求めたいパディング長)
既知の I[i][j](j > 16-pad の桁)について
R[j] = I[i][j] XOR pad … 末尾を pad で揃える固定値
未知の1バイト R[16-pad] を 0x00..0xFF で総当たり
パディング OK が出たら
I[i][16-pad] = R[16-pad] XOR pad
pad を 1 増やして次のバイトへ繰り返す
これを16回繰り返せばブロック1つの中間値が丸ごと埋まり、平文16バイトが復元できます。コストは「1バイトあたり最大256回」×16バイト=最悪4096回のリクエストで、256^16 の総当たりとは比べ物にならない軽さです。任意ブロックに同じ操作を適用すれば、IV と先頭ブロックを含め暗号文全体を順に復号できます。鍵は一度も登場しません。
なぜオラクルが致命傷なのか
本質は CBC が「暗号文の改ざんに無防備」かつ「復号の途中結果を観測可能」 な点にあります。攻撃者が R[15] を1ずつ変えるたび、サーバーは「合格/不合格」という1ビットを返す。この1ビットの差が、本来秘密であるはずの中間値を一意に絞り込みます。エラーメッセージが同一でも、応答時間の差や接続切断の有無といったサイドチャネルがあれば同じ情報が漏れます。
パディングエラーと MAC エラーで別のメッセージを返すのは論外ですが、両者を同じ文言にしても安全とは限りません。検証を「パディング確認 → MAC 確認」の順に2段で行うと、パディング不正のとき MAC 計算を飛ばすぶん応答が数マイクロ秒速くなる。この時間差がタイミングオラクルになります。これが Lucky13 の正体です。
POODLE と Lucky13:同じ穴の別の顔
どちらも「CBC + 復号後に検証」という設計(MAC-then-Encrypt 系)に根があります。
| 攻撃 | 年 | 突く点 | なぜ成立するか |
|---|---|---|---|
| 古典パディングオラクル | 2002 | 明示的なパディングエラー応答 | エラーが種類別に返り、合否が直接漏れる |
| POODLE | 2014 | SSL 3.0 のパディング仕様 | 末尾バイトしか検証せず、CBC をブロック単位で削れる |
| Lucky13 | 2013 | MAC 検証の応答時間差 | パディング確認と MAC 確認の処理時間差がオラクルになる |
POODLE はとりわけ実害が大きく、攻撃者が TLS 接続を妨害して**安全な新プロトコルから脆弱な SSL 3.0 へ引きずり下ろす(ダウングレード)**ことで成立しました。対策は SSL 3.0 の全面廃止であり、現在は TLS でこの旧バージョンを無効化するのが標準です。
根本対策:Encrypt-then-MAC
対症療法(エラーを統一、応答時間を一定化)は実装漏れと隣り合わせで脆い。設計で断つのが正解です。
| 方式 | 処理順 | 復号前に改ざんを弾けるか | パディングオラクル |
|---|---|---|---|
| MAC-then-Encrypt | MAC 付与 → 暗号化 | 弾けない(先に復号が要る) | 残りやすい |
| Encrypt-then-MAC | 暗号化 → MAC 付与 | 弾ける(MAC 不一致で即破棄) | 原理的に消える |
| AEAD(AES-GCM 等) | 暗号化と認証を一体化 | 弾ける(タグ検証が先) | そもそも起きない |
ポイントは検証の順番です。Encrypt-then-MAC では、受信側はまず暗号文に対する MAC を照合し、一致しなければパディングを見る前に問答無用で破棄します。攻撃者が R を細工しても MAC が合わず、復号処理に到達できない。送ったメッセージが必ず同じ「MAC 不正」で弾かれるので、合否のばらつき=オラクルが消えます。MAC の比較は定数時間比較で行い、ここでも時間差を作らないのが鉄則です(MAC とハッシュの違いは ハッシュ化と暗号化の違い を参照)。
自前で CBC + HMAC を組み合わせるのは事故のもとです。認証付き暗号(AEAD)である AES-GCM や ChaCha20-Poly1305 を使えば、暗号化と改ざん検知が一体で、パディング検証という工程自体が存在しません。TLS 1.3 は CBC スイートを全廃し AEAD のみに絞りました。新規実装では「CBC を選ばない・SSL 3.0/TLS 1.0 を無効化する・AEAD を既定にする」を出発点にしてください。
「パディングオラクル攻撃で破るのは鍵か?」→ 鍵ではなく暗号文を復号する。「必要な情報は?」→ パディング検証の合否という1ビット(応答内容・時間・接続状態のいずれでも漏れる)。「根本対策は?」→ Encrypt-then-MAC または AEADで、復号前に改ざんを弾くこと。エラー文言の統一は補助策にすぎない、と押さえるのが要点です。
CBC を1バイトずつ崩すこの攻撃は、「暗号化さえすれば安全」という思い込みが完全性(改ざん検知)の欠落で破綻する典型例です。秘匿と改ざん検知が別物である点は 暗号の基礎、検証に使う MAC の位置づけは ハッシュ化と暗号化の違い、通信路でこれらを束ねた全体像は TLS / SSL を合わせて確認してください。
セキュリティ Article
パディングオラクル攻撃の原理(CBC を1バイトずつ復号する)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
CBC
比較で見る軸
難易度: advanced / カテゴリ: セキュリティ / タグ数: 5
導入後に効く点
鍵を破るのではない。前ブロックの暗号文を細工し、復号後の末尾が正しいパディングになる値を総当たりで探すと、復号途中の中間値が逆算できる仕組み。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- セキュリティ
- タグ数
- 5
判断チェックリスト
- 自社の用途が「CBC / 暗号」に近いか確認する。
- 強みである「パディングが正しいか否か(1ビット)をサーバーが区別して返すだけで、攻撃者は鍵なしに CBC 暗号文を1バイトずつ復号できる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。