SSL3.0/TLS1.0 に脆弱性
2011年9月29日 11:30
ある Anonymous Coward 曰く、
9 月 21 〜 23 日に開催されていたセキュリティ会議 ekoparty において、SSL 3.0 および TLS 1.0 の CBC モードに対する、いくぶん実用的な盗聴方法 (BEAST) が発表された (ITmedia エンタープライズの記事より)。
この攻撃は blockwise-adaptive chosen-plaintext 攻撃 (Gregory V. Bard 氏による論文) を用いることで暗号化されたデータを復号化できるというもの (yebo blog の記事) 。今回の発表の論文は http://insecure.cl で公開されていたのだが、現在は著者からの要求により削除されている。続報は insecure.cl のサイトか Twitter アカウント @insecurechile にて、とのことなのだがスペイン語なので読解には苦労されることだろう。
この問題は TLS1.1 や 1.2 には存在しないが、実装が少ない現状では、多くの https 通信が危険な方式で暗号化していることになる。
The Tor Blog の記事の一部を訳してみたので参考にしてほしい。
攻撃手法: 基本的な背景
ここではコンピュータのことを少しは知っていて、xorがどう作用するのか分かっている前提で話をする。
初心者のために、まずブロックサイファーについて話そう。ブロックサイファーは、平文データの小片を、秘密鍵に基づいて同じサイズの暗号データに暗号化する道具だ。
実用上、一度に小さな断片だけではなく、もっと大量のデータを暗号化したい。たとえば 16 バイトブロックの (AES のような) ブロックサイファーで 256 バイトのメッセージを暗号化したいとしたらどうするか。たいていは最初に「16 バイトごとに区切ってそれぞれを暗号化しよう」と言う。昔はそういう考えでやっていた (ECB すなわち electronic codebook と呼ばれる) が、それには重大な問題が幾つかある。特に、平文に同じ 16 バイトブロックが何度も出てきたら、暗号文も同じ場所に同じブロックが出てきてしまう。
わかった、じゃあ馬鹿でもなければ ECB を使わないんだな。ところが、CBC すなわち cipher block chaining と呼ばれるモードを使う人がいる。CBC では、メッセージを暗号化する前にまず無関係なランダムブロック一つ (IV すなわち initialization vector) を作り、これを最初の暗号文ブロックとする。それから、平文の各ブロックを暗号文ブロックに暗号化していく際には、まずその平文を前の暗号文ブロックと xor するんだ (だから最初の平文ブロックは IV と xor して暗号化する。それを次の平文ブロックと xor して暗号化し、それを次の、と続ける) 。
TLS およびその前身 SSL は、多くのアプリケーションが暗号化データを送るために使っている暗号化プロトコルだ。こいつらはブロックサイファーの大部分に CBC を使う。残念なことに、TLS バージョン 1.1 より前のこいつらは、大変な間違いをしてしまった。TLS メッセージごとに毎回新しいランダム IV を使うのではなく、前のメッセージの最後の暗号文ブロックを、次の IV として使ったのだ。
どうしてこれがダメなのか。IVというのはランダムっぽく見えればいいのではない; 攻撃者が予測できないものでなくてはいけないのだ。もし君が x という IV を使うつもりであることが分かっていれば、私は君に [(NOT x) xor y] という平文ブロックで始まるメッセージを送るよう仕組むことにより、私に y を暗号化したものを送ってもらえるのだ。
これはそれほど悪い事態には見えないのだが、Wei Dai と Gregory V. Bard は、これを使って特定の暗号文が特定の平文に対応しているかどうか知る方法を見付けたのだ。攻撃者はユーザに C' xor p を暗号化させる。ここで p は原文の可能性がある平文、C' は直前の暗号文ブロックだ。その平文が当たっていると、ユーザの SSL 実装は最初にそのブロックを暗号化したときと同じ暗号文を出力してしまう。
これでもまだ大したことはなさそうに見える。この攻撃を実現するために、敵は君のインターネット接続を見張っている必要があるし、次の TLS レコードを任意の文字列で始めさせることができなければいけないし、以前に送った秘密の発言についてある程度推測できなくてはいけないし、それに対応する TLS ストリームがどこの部分なのかも推測しなければいけない。
しかしながら、暗号業界人は回避策を実装した。備えあれば憂いなし。TLS プロトコルのバージョン 1.1 では各レコードが新鮮な IV をもらうようにして、攻撃者が次のメッセージの IV を前もって知ることができないようにしたのだ。OpenSSL も修正を入れて、TLS レコードを送る際に毎回、空の TLS レコードを先に一つ送ってから、本文の入ったレコードを送るようにした。空の TLS レコードは CBC の状態を変更させるので、本文には攻撃者から予測できない新しい IV を与えるのと同じ効果が得られるのだ。
だが、こうした修正はウェブ世界にあまり広まっていない。TLS 1.1 は 2006 年に標準化されているのに広く実装・実用されていないし、OpenSSL の「空レコード」トリックも、完全準拠でない SSL 実装で動かなくなるものがあると判明したので、オフにしている人が多い (OpenSSL のマニュアルは、オフにしても「たいてい安全」だとさえ言っている) 。
当時はそれが理にかなっていると思えたのだろう。平文を推測するのは難しい: 3.4 x 10^38 通りの値があるのだ。だがよく言うように、攻撃は巧妙さを増す一方なのだ。
今回の手法の新しいところ
見たところ、Juliano Rizzo と Thai Duong には二つの点で貢献がある (誤解があれば訂正を願う; 原文を詳しく見たわけではないんだ!) 。第一に、Dai の攻撃の実に巧妙な変種を実装するシナリオを思いついたことだ。
Rizzo と Duong が提示した例そのものではなく、単純化したものを挙げよう。まず何らかの理由で、ユーザが秘密情報 (たとえば cookie) を TLS レコードごとに毎回送るものとする。さらに攻撃者はその秘密情報の直前のレコード冒頭に任意の文字数の平文を挿入させるよう仕組むことができるものとする。それで各レコードの平文は「毒|秘密」となる。「毒」というのは攻撃者の任意の情報で、「秘密」は秘密情報だ。最後の条件として、攻撃者はユーザに好きなだけたくさんのレコードを送らせることができるものとする。
ブロックの区切りの場所を決める権限があるというのは大きな利点になる。16 バイトの平文ブロック全体を毒で埋めるのではなく 15 バイトだけ埋めるとしよう。するとそのブロックは 15 バイトを攻撃者が支配し、1 バイトは秘密情報になる。
うひょ! たった 1 バイトなら可能性は 256 通りに過ぎないから、攻撃者は順番に試していって当てることができるぞ。最初の 1 バイトが当たれば次は、14 バイトの毒と 1 バイトの (ゴリ押しで当てた) 解読済み情報と 1 バイトの未解読秘密情報を送らせればいい。今回も可能性は 256 通りに過ぎないので、昔ながらの試行錯誤で十分だ。
Rizzo と Duong はこれを、攻撃者が実際にはブロックの開始位置を支配していないものの偶然 (あるいは推測) によって知る場合に拡張する方法や、その他この攻撃手法の拡張を示している。
第二の巧妙な切り口は、この攻撃をウェブブラウザに作用させる方法を実際に見付けたことにある。これは偉業と言っていい! この攻撃を実現するには、十分に制御した要求をウェブクライアントから送らせるよう仕組む方法を見付けなければいけないし、しかもそれを繰り返しやらなければいけない。見るからに大変な HTTP ハックだったろうが、それをやってのけたようだ。より詳細な情報が Eric Rescorla のブログにあるし、もちろん Juliano と Thai が論文を出せば子細に見るべきものがさらに増えるだろう。それにしてもこいつは本当に頭のいい方法だと思う。
[注意: もう一度言っておくが、上の内容には間違いがあるかもしれない; もしそうなら、朝起きてからか、それより前に直すつもりだ。私よりも詳しく知っている人はどうかダブルチェックしてほしい。]
スラッシュドットのコメントを読む | セキュリティ | mainpage