2013年08月10日

サーバー側・クライアント側でのBEAST/CRIME系攻撃への処方メモ

今更過ぎるけれど、centos6.xのopensslがまだ1.0.0でTLS1.1非対応という現実に直面したので回避方法を考えてみるメモ。

(追記:ブラウザ側でのハックの困難性があまりに甘かったので困難性を追記。)


BEASTやCRIME攻撃として提案された手法の本質は、同じ秘密情報を含むHTTPSリクエストをたくさん発生させることで、SSL圧縮ブロックや暗号ブロック境界の選択平文攻撃によって、秘密情報を1バイト単位で少しずつ盗むというものだ。
http://j-net21.smrj.go.jp/develop/digital/entry/001-20120229-01.html
CRIMEなら例えば、リクエストに適当な文字列を1バイト追加して、SSL圧縮が起きればそのバイトが秘密情報に含まれる事が分かる。これを繰り返して、秘密情報全体を決定していく。
http://www.scutum.jp/information/waf_tech_blog/2012/09/waf-blog-014.html

攻撃に必要なたくさんのHTTPSリクエストを発生させるには、別個にブラウザやそのプラグインの脆弱性などを必要とする。(追記:原理的にはscriptタグなどで外部ドメインから直接叩く、というのはアリそうだけど、正しく外部呼び出しがコントロールされたHTTPSサーバーなら回避できるはず)つまり、javascriptやRefreshなどの悪意あるリクエストを生成するコードをブラウザに注入できるものの、クッキーのhttpsonlyなどによって、スクリプトだけでは秘密情報を取得できない場合を対象にしている。
また、囮無線LANアクセスポイントなど、パケットキャプチャ(少なくともパケットのサイズやタイミングの推定)が容易にできることも前提になる。

提案されている攻撃では、バイトシフトや圧縮を利用して最大256通り・平均128通りのリクエストを試すことで、1バイトの秘密情報を奪うことが出来る。実際にはCookieなどの秘密情報はBase64やhexで書かれている事が多いので、最悪だと平均8回で4bitの情報が漏れることになる。
秘密情報がSHA-1 160bitのhexなら、わずか320クエリ程度で完全に特定できるので、単純にリクエストの頻度によってサーバーサイドでフィルタする方法では、ブロックする閾値が低すぎて通常利用に差し支えるだろう。


サーバー側HTTPSプロトコルでの対応
対処法としては、HTTPSサーバーの設定で、CBCモード暗号を使わず、SSL圧縮を無効にすれば、今知られている手法に対しては一応対応できる。ただし、圧縮やタイミングをサイドチャネル攻撃は様々なレイヤー・状況下で発生するので、完全に防ぐのは無理かもしれない。対症療法的に、暗号にCBCを使わないRC4を使うというものもあるが、それは暗号強度の面で問題が有る。
http://tetsutalow.hateblo.jp/entry/2013/04/02/053927


サーバー側アプリケーションでの対応
一方、アプリケーションレベルでCRIMEを含む圧縮率やタイミングによるサイドチャネル攻撃の排除方法としては、秘密情報を毎回変化させてしまう、という方法が挙げられる。
これらの攻撃手法は、秘密情報が少しずつ漏れるという特徴があるので、クライアントに保存するログイン情報を、毎回サーバー側で自動生成してしまう。
ただし、Cookie送信自体はクライアント側だけでパイプラインして複数回行えるので、リクエストとレスポンス到達の時間差によっては、サーバーが攻撃を検知してクッキーを再設定する前に攻撃を終わらせられるような改良手法が出てくるかもしれない。


クライアント側HTTPSでの対応
CBCモードでTLS1.0がIVを使いまわす事を利用したBEAST攻撃は、接続の切断や無効なリクエストの付加でIVを定期的にリフレッシュすることで対処できる。また、SSL圧縮に対応させないことで、既知のCRIMEに対処できる。

SSL/TLS実装が改修されていない、あるいは密結合していないブラウザの場合、HTTPクライアント側で、ゴミデータをリクエストに追加するという方法も考えられる。

一つは、GETやPOSTに先行して /favicon.ico (ドキュメントルート)など へのHEADリクエストを挿入してしまう方法。
HEADリクエストは副作用が無いので、404でも200でも構わない。これでIVを挿入したリクエストの末尾の暗号ブロックにリフレッシュ出来る。

もう一つはランダムな内容とある長さの独自HTTPヘッダを秘密情報の前後に挿入すれば、バイト境界を利用するタイプの攻撃は排除できる 難しくなる。たとえば
X-NONCE-1: ランダム長さの乱数列
Cookie: xxxxx;
X-NONCE-2: ランダム長さの乱数列
というように、ブラウザがランダム長の乱数で秘密情報の位置をシフトしたり、圧縮辞書を変化させてやれば、攻撃したいバイト境界がリクエストの度に変化するので、攻撃を著しくある程度困難に出来る。(追記、ただバイトシフトするのではBEASTは1/可変長にしかならない。圧縮系には意味があるが)

ブラウザはどれが秘匿すべき情報なのかアプリケーションの詳細を知らないし、独自ヘッダではクエリ文字列にセッション情報を保持するようなアプリケーションには対処できない(ただjavascriptを注入された時点でクエリ文字列は取得されているはず)、といった問題はあるけれど、この手法はSSL実装をOSに依存した軽量なブラウザや、ブラウザの追加アドオンなどでできるので、BEAST等に脆弱だが改修できない古いHTTPSサーバーやクライアントライブラリに対して、ユーザーやブラウザアプリ開発者の対抗手段時間稼ぎとして利用できる。



サーバー側のopensslバージョンによる制限
クライアント側が完全に実装されるまで、現時点ではサーバー側で、TLS1.1以降やGCMモードなどのバイトシフトによる攻撃が難しいモードを使い、SSL圧縮を無効にするといった方法で対処することになる。
ところが、そのために必要なopensslは1.0.1以降で、まだ数の多いRHEL6.xではいまだ1.0.0のため、互換性を捨てて1.0.1以降にするか、TLS1.0のRC4しか回避する手段がない。そしてRC4にもまた脆弱性が見つかっている。

1.0.1以降が入っているなら、TLS1.1以降を有効にしているクライアントに対しては、RC4のような古い暗号を優先せず、AES-GCMなどを用いるべき。


秘密情報のないサービス
これらの攻撃は秘密通信をリークするだけなので、秘密情報を扱わないアプリケーションには影響しない。
フリーソフトウェアの静的な配布サイトのように、誰でも匿名でダウンロード出来る情報しかないウェブサイトなら、漏れて困る情報はない。
HTTPSでダウンロードした内容やHTTPSのウェブサイトに記載されたソフトウェアの証明書フィンガープリントが改ざんされている、ということは上記の手法では考えにくい。

結局自分のアプリ配布用サーバーはRC4ということで妥協しておく。

nginx設定メモ
    ssl_prefer_server_ciphers on;
    ssl_protocols       SSLv3 TLSv1 TLSv1.1 TLSv1.2;  #実際にはTLSv1.1以降使えていない
    ssl_ciphers  AESGCM:RC4:HIGH:!MD5:!aNULL; #RC4以降しか使えていない
    # AESGCMと省略出来る事に気づいたので変更

SSLチェック https://sslcheck.globalsign.com/ja/sslcheck?host=app.usb0.net
ラベル:Beast crime CentOS
posted by ko-zu at 11:05| Comment(0) | TrackBack(0) | セキュリティ | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック
×

この広告は90日以上新しい記事の投稿がないブログに表示されております。