# なんでこんな事を検討してるんだとかはあまり考えたくないのでやめておく
# ブラウザではないのだけど
そのままランダムバイトシフトによる方法は効率が悪い。というのを昨日気づいていなかったので訂正を兼ねて。
CBCでは
平文ブロックの列 ..., Pn-1, Pn , Pn+1, ...
暗号ブロックの列 ..., Cn-1, Cn , Cn+1, ...
に対して、
E( Cn-1 ^ Pn) = Cn
がなりたつ。
BEASTでは
(1) 攻撃者はブロック境界を制御できる
(2) ある平文ブロックPxに秘密情報が1バイト含まれ残りの部分は知っている
(3) かつある暗号ブロックCn-1に対して、次の平文Pnを制御できる
(4) 次の平文Pnを攻撃者が決定する前に、Cn-1とそれ以前の暗号文ブロックを傍受済み
を組み合わせる。
攻撃者はPxブロックの暗号文Cxを傍受できるが、直接残りの1バイトを計算することはできない。そこで攻撃者はセッションを再利用して平文Pnで始まるリクエストを発行する。
このとき、次の平文Pnとしてブラウザに送らせるべき内容は、想定している256種のPxの一つ Pxi (i= 0...255)について、Cn == Cxを仮定して、Pn ^ Cn-1 == Pxi ^ Cx-1 から、Pn = Pxi ^ Cx-1 ^ Cn-1 と計算できる。(4)からCn-1を傍受できるので、Pnを計算するための不確定要素はPxiの256通りのみになる。
Cn が予想通り Cxと一致すれば、 Pxiが正解だったことが分かる。失敗であれば、盗聴した最後の暗号ブロックを新たにCn-1として、次のPxiを調べていく。つまり平均128*トークン文字数程度の連続リクエストができればPxiから衝突を発見できる。トークンが事前にhexとわかっていれば、平均8リクエスト*トークン文字数ですむ。
TLS1.1以降で導入されるIVの強制的な更新では、暗号鍵・セッションを再利用する場合、新しいリクエストでは以前の暗号ブロックCn-1を使わず新しいIVにすることで、バイトごとの総当りを不可能にする。つまり(4)を防ぐ。攻撃者は新しいIVを事前に知ることが出来ないので、適切なPnを生成できない(Cn-1が足りない)。
TLS実装側から言えば、CBCモードの暗号器を使うなら、平文入力をバッファして次の平文ブロックPnが確定するまで直前の暗号ブロックCn-1の出力をブロックし、平文バッファをフラッシュしてMACを送った後はIVを変更することで、(4)が成立しないことを保証する。
TLS1.1に対応したクライアント・サーバーならこれでいいが、CBCがデフォルトのままのサーバーと、TLS1.0クライアントライブラリを使わなければならない場合を考える。
まずTLSセッションを毎回破棄してしまう方法があるが、keep-alive必須とされているし、お互いにあまりにも効率がわるい。
openssl実装は設定によってはパディングを送信できるようだが、少なくとも(TLS1.0しかない)1.0.0でがデフォルトにはなっていないようだ。
クライアントだけで出来る一つは、冗長なリクエストを送ることで、IVの更新に替える。たとえば、全てのリクエストの前に、/へのHEADリクエストを送るなど。続くjavascriptで生成されたリクエストはHEADリクエストの最後の暗号ブロックをIVとして使うので、攻撃者はPnを生成できない。なおN回に1回HEADを送るのでは、攻撃を'(N-1)/N倍に遅くすることしか出来ないのでほぼ意味が無い。
これらはいずれも(4)を防ぐことでBEASTから守る。
一方、追加ヘッダで可変長の乱数列を追加する方法は、攻撃者がPxの状態を知ることが出来るという前提を崩す方向を考える。つまり(2)のPxの特定を難しくする。これははっきり行って効率が良くない。
乱数列の長さが不明なので、攻撃者はPx候補の前の暗号化ブロックCx-1を複数のブロックから見つけ出す必要がある。
これが成功する確率は、乱数列のバイト数をkとし、秘密が1バイトだけで左15バイトが既知なら、1/kになる。よさそうだが、2バイト目への攻撃もまた1/kで推定できてしまう。つまり困難性はk/2倍程度しか上がらない。
200バイト可変シフトさせて、突然クライアントからのリクエスト数の桁が100倍も増えれば、流石にレートリミットが効くだろうけれど、全体平均してk/2倍にしかならないので暗号としては余裕が無い。もっとも、Cookieに保存するトークンの長さを(k/2)倍にするのと同じだけの効果がある、という意味では大きい。
バイトシフトによる対処では足りないなら、秘密情報の位置をシフト「させない」必要が出てくる。同一ブロックに3〜4バイトも秘密情報が含まれれば、総当りは急激に難しくなる。つまり(2)の不確定要素を2バイト以上にする。
だがこれはjavascriptがcookieをセットできるのでうまく行かない。javascriptで重要なトークンより前に別のキーをセットしたり、長さを変更できてしまう。
結局のストリーム暗号としてのCBCモードの限界として、クライアント側で使えそうな防御手段はあまりない。
弱い暗号やCBCを強制するサイトからは都度ログアウトする、くらいか。