目次
- 概要
- 経緯
- 何が問題か
- 経緯説明(1)基本的なチェックは対処済みだった
- 経緯説明(2)ハイフンをアンダースコアに変えるトリックは対策済み
- 経緯説明(3)海老原氏が発見したトリックとは
- 経緯説明(4)KDDIに連絡→翌日に対処
- 実証例
- 外部からJavaScriptを実行できる条件
- 影響を受けるサイトの条件
- 影響
- 対策
- 今回の問題は、端末あるいはau設備の脆弱性なのか
- まとめ
概要
以前、「EZwebの2011年秋冬モデル以降の変更内容とセキュリティ上の注意点」にて、auの2011秋冬モデルにてEZwebとPCサイトビューア(以下PCSV)のゲートウェイが統合される(以下「新EZサーバー」と表記)ことによるセキュリティ上の懸念と、Cookieの仕様変更について予測しました。両者は結果として「アタリ」でした。本稿では、セキュリティ上の問題について報告します。なお、セキュリティ上の問題はKDDIに報告し、既に解消しています。経緯
経緯を時系列で示します。全て2011年です。- 9月28日(水):秋冬モデルよりEZwebとPCSVのIPアドレスが統一されると発表(魚拓)
- 11月9日(水):F001が関西など一部地域で発売開始。関東は11月10日発売開始。
- 11月10日(木):徳丸がF001を購入。検証を開始するも、この日のうちには問題を発見できず。
- 11月11日(金):早朝、OpenPNEの海老原昂輔(@co3k)さんから、PCSVにてEZ番号を偽装できる旨の連絡と、OpenPNEの対応と情報公開の相談を受ける。KDDIに連絡して対処してもらうことを優先し、公表をしばらく見合わせることを合意
- 11月11日(金):ツテを通じてKDDIに連絡
- 11月12日(土):F001のPCSVのIPアドレスが変更されていることを確認。成りすましの危機は回避される。この状態のまま現在に至る
- 11月28日(月):EZfactoryにて「※ セキュリティ確保のため、EZブラウザとPCサイトビューアーは、従来通り異なるIPアドレス帯域を使用しております」と発表(直リンク)(魚拓)
ということで、連絡の翌日には回避策がとられました。迅速な対応だと思います。
何が問題か
ここで扱っている問題は、PCSVのJavaScriptを悪用して、ケータイWebサイトの「かんたんログイン」なりすましの可能性です。基本的には、以下のエントリで説明した内容です。携帯JavaScriptとXSSの組み合わせによる「かんたんログイン」なりすましの可能性
このレポートではXSSによる攻撃のみに言及していますが、その後の研究により、DNSリバインディング攻撃を使っても攻撃が可能であることが分かっています。もっとも、ケータイブラウザのJavaScriptでは、XMLHttpRequestオブジェクト(以下XHR)によるHTTPリクエストヘッダを変更に大幅な制限がかけられたため、この攻撃は成立しません。一方、XHRに大きな制限をかけたことで、ケータイJavaScriptはインターネット一般のJavaScriptとの互換性が大きく損なわれました。
今回の問題は、ケータイブラウザ(iモード、EZweb、Yahoo!ケータイのブラウザ)ではなく、PCSVを使った攻撃であることが、従来とは異なります。PCSVからの攻撃が可能になった理由は、F001以降のEZweb端末で、EZブラウザとPCSVの使うゲートウェイが共通になったためです。つまり、かんたんログインの前提として、ケータイブラウザからのリクエストであることを確実にチェックする方法として、リモートIPアドレスを用いていたのに、その同じIPアドレスにPCSVからのリクエストが混じるようになったためです。
経緯説明(1)基本的なチェックは対処済みだった
KDDIは、これによる危険性を承知していたようで、F001のPCSVのXHRには以下の処置が施されていました。
- リクエストヘッダX-UP-SUBNO(EZ番号)が追加できない
- リクエストヘッダUser-Agentが変更できない
これらにより、PCSVを使ってもEZ番号の詐称ができないよう配慮されていました。User-Agentの変更もできないようにしている理由は、EZwebかPCSVの区別をつけるためと、au以外の事業者の端末に成りすましができないようにとの配慮でしょう。
経緯説明(2)ハイフンをアンダースコアに変えるトリックは対策済み
CGIやPHP等一部の言語では、foo-barという形のリクエストヘッダは、HTTP_FOO_BARという形式で受け取ることになります。これは、CGIの仕様として、リクエストヘッダを環境変数にして受け渡す際の約束です(下表)。PHPは、CGIの形式を踏襲しています。HTTPリクエストヘッダ | 環境変数として受け取る形式 |
foo-bar | HTTP_FOO_BAR |
User-Agent | HTTP_USER_AGENT |
X-UP-SUBNO | HTTP_X_UP_SUBNO |
一方、Java EE(Servlet)(HttpServletRequest#getHeaderメソッド)や.NET(Request.Headersプロパティ)では、リクエストヘッダを元のまま受け取ります。以下、CGIの形式の場合について議論します。
CGI等では、X-UP-SUBNO(EZ番号)はHTTP_X_UP_SUBNOというキーで受け取るので、最初からX_UP_SUBNOというリクエストヘッダにすれば、CGIプログラムやPHPスクリプト側ではEZ番号として受け取る可能性があります。
HTTPリクエストヘッダ | 環境変数として受け取る形式 |
X_UP_SUBNO | HTTP_X_UP_SUBNO |
この方法については以前テストしたことがあり、WAS Forum 2010で発表しました。このスライドの54ページ以降を参照下さい。ただし、このトリックは、ソフトバンクの一部端末でかつEnd-to-EndのSSLの場合のみ有効で、平文通信の場合はゲートウェイ側でチェックされているようです。これらの事実から、SSLではかんたんログインを受け付けるなという結論になります。
F001でもこのトリックが使えないかと思い、購入直後からチェックしましたが、ハイフンをアンダースコアに変更しても、EZ番号やUser-Agentに相当するヘッダは送信できませんでした。
アンダースコアがダメ(ちゃんとチェックされていた)だったので、ヌルバイトや改行など、過去問題になったことのある手法を試してもチェックをできなかったので、その日(11月10日)はあきらめて寝てしまいました。
経緯説明(3)海老原氏が発見したトリックとは
ところが、その日の深夜に海老原さんからメールが入っていました。メールによると、X.Up.Subnoというヘッダを送る(ハイフンやアンダースコアではなくドットを使う)ことで、PHPスクリプトからはHTTP_X_UP_SUBNOとして受け取れるというのです。確認してみると、CGIプログラムおよびPHPスクリプトでは確かにそうなります。海老原さんからの相談は、既にOpenPNEはF001のIPアドレスを有効にしてかんたんログインが可能にする対応を配布済みだが、上記トリックにより成りすましができる(可能性がある…後述)。リストを取り下げると、その理由も説明しなければならず、他のサイトに対して攻撃されるリスクがあるので悩ましい、というものでした。
これに対して、徳丸からは、まずはKDDIに通報して、速やかに対処されればそれでよし、遅くなるようであればあらためて公開方法を考えようとアドバイスしました。海老原さんも合意され、徳丸からKDDIに連絡することになりました。
経緯説明(4)KDDIに連絡→翌日に対処
徳丸からは、信頼できる方を通じてKDDIの該当部署にピンポイントに連絡を取りました。至急動いて下さるという返事を頂いたので、しばらく待つことにしまして、その旨を海老原さんにも伝えました。すると、翌日になって変化がありました。PCSVからのリクエストのリモートIPアドレスが変化しました。
11月12日朝までのIPアドレス:111.107.116.*
11月12日夜以降のIPアドレス:111.87.241.*
すなわち、11月12日の朝までは、EZfactoryにIPアドレス帯域として記載されたIPアドレスからリクエストが来ていましたが、同日の夜(21:55頃最初観測)以降は、別のIPアドレスにPCSVが移されたことになります。
PCSVからのリクエストが別IPになれば、PCSVを用いた「かんたんログイン」の成りすましはできなくなります。
実証例
検証用の比較的シンプルなスクリプトを以下に示します。User-Agentは実機そのまま、EZ番号は、0509999…で始まる架空のものにしてあります。検証用HTML --------------------- <html> <head> <script> function test() { var requester = new XMLHttpRequest(); requester.open('GET', 'dump.php', true); requester.onreadystatechange = function() { if (requester.readyState == 4) { onloaded(requester); } }; requester.setRequestHeader("User.Agent", "KDDI-FJ31 UP.Browser/6.2_7.2.7.1.K.8.160 (GUI) MMP/2.0"); requester.setRequestHeader("X.UP.SUBNO", "05099999999999_vi.ezweb.ne.jp"); requester.send(null); } function onloaded(requester) { res = requester.responseText; document.getElementById('result').innerHTML = res; } </script> </head> <body onload="test()"> <div id="result"></div> </body> </html> dump.php --------------------- <?php echo "UA:" . htmlspecialchars($_SERVER['HTTP_USER_AGENT']) . "<br>"; echo "EZNO:" . htmlspecialchars($_SERVER['HTTP_X_UP_SUBNO']); ?>
F001のPCSVで実行した結果の画面を下図に示します。User-AgentとEZ番号が偽装されている様子が分かります。
外部からJavaScriptを実行できる条件
この節は技術的に誤りでした。海老原さんの日記によると、F001のPCSVはアドレスバーからのJavaScript実行が可能なので、全てのサイトで、任意のJavaScriptを利用者が実行できるそうです。この同一生成元ポリシー回避として、よく使われるテクニックは、クロスサイト・スクリプティング(XSS)です。攻撃対象サイトに1箇所でもXSS脆弱性があれば、それを悪用してJavaScriptを実行することができます。
もう一つの方法は、DNSリバインディング攻撃です。ケータイのDNSリバインディング攻撃については、「iモードIDを用いた「かんたんログイン」のDNS Rebinding脆弱性」を参照下さい。この問題に対して、対策を施しているサイトはDNSリバインディング攻撃によるJavaScript実行はされません。F001のPCSVでは、Hostヘッダの書き換えはできません。
影響を受けるサイトの条件
この問題の影響を受けるサイトは以下の全ての条件を満たすサイトです。- かんたんログインを実装している
- 新EZサーバーのIPアドレスを許可している
- ヘッダ名の記号をアンダースコアに変更する言語を使っている(CGIやPHPなど)
JavaScriptを外部から実行する手段がある(前項参照)
これらの条件を全て満たすサイトは、かなり存在する(存在した)と予想しています。
影響
前項の条件を満たすサイトでは、以下の影響があります。- 利用者の介在なしに、任意の利用者へのなりすましが可能
ただし、利用者のケータイIDは既知であるとします。
ケータイIDの収集は容易です。攻撃に先立ち、ケータイ向けWebサイトを開設して利用者を集めるだけで、閲覧者のケータイIDを収集することができます。また、ランダムに生成したケータイIDを攻撃に用いることも可能です。
サイトの実装によっては、auの利用者だけでなく、NTTドコモやソフトバンクの利用者に成りすましできる場合があります。その条件は、リモートIPアドレスによってキャリア判定していない場合です。言い換えれば、User-AgentやケータイIDによってキャリア判定している場合は、これらヘッダがJavaScriptにより改変可能なので、NTTドコモやソフトバンクの端末に成りすまし可能です。
しかし、XSSやDNSリバインディング攻撃は受動的攻撃であり、罠を閲覧した利用者のみが影響を受けるのに対して、ケータイIDの変更による成りすまし攻撃は、利用者の介在なしに任意の利用者に成りすましできる点が異なります。すなわち、この問題により非常に多数の利用者が影響を受ける点が問題です。
ひょっとすると、従来XSSやDNSリバインディング攻撃の脅威を知りつつも、「影響が小さいので対策しない」という判断を(好ましくはないですが)しているサイトもあるかもしれません。そのようなサイトに対しても大きな脅威が生まれます。
対策
PCSVによるかんたんログイン成りすましは、既にKDDIにより対策されていますが、もし対策されていないとすると、以下が対策になります(なりました)。- XSS脆弱性をすべてなくす かつ
- DNSリバインディング攻撃対策をする(ホスト名のチェックなど)
これらは、勝手にJavaScriptを実行されないようにする対策です。今回の問題がなくても、上記は必須です。
※追記:今回の問題に対して効果がないので取り消しましたが、上記が元々必須であることには変わりません。
- HTTPリクエストヘッダを生のまま取得できる関数を使用する
Java Servlet(Java EE)や.NETでは、これは元々実現されています。
PHPを使う場合は、getallheaders()関数を使うと、生のHTTPリクエストヘッダを取得できます。
これらにより、X.Up.Subnoと指定したヘッダは、X.Up.Subnoのまま取得されることになります。HTTP_X_UP_SUBNOにはなりません。
さらに、かんたんログインの安全性を保つための必要条件として以下があります。これは、「間違いだらけの「かんたんログイン」実装法」を@ITに寄稿した際にまとめたものですが、読者の便宜のために再掲します。DNSリバインディング攻撃対策については重複しています。
- 携帯電話事業者のゲートウェイからのアクセスのみを受け付ける(IPアドレスチェック)
- リモートIPアドレスを基にキャリア判定を行う(User-AgentなどHTTPリクエストヘッダで判定してはいけない)
- 契約者固有IDとしてはiモードID、EZ番号、ユーザーID(ソフトバンク)のみを用いる
- HTTPSではかんたんログインを受け付けない
- Hostヘッダのチェックまたは名前ベースのバーチャルホストを設定する
- ソフトバンクの非公式JavaScript対応端末へ何らかの対処を行う
非常に多くの条件ですが、これらで本当に安全になるかは誰にも分かりません。そのため、この機に、かんたんログインをやめ、パスワード認証等に移行することを真剣に検討しましょう。
今回の問題は、端末あるいはau設備の脆弱性なのか
さて、これまで説明したF001のPCSVの問題は、端末ないしau設備の脆弱性なのでしょうか。私は、KDDIが責任を持つべき脆弱性ではないと考えています。KDDIは、かんたんログイン手法に対して、なんら保証をしていないからです。
とはいえ、完全に「シロ」と言い難い面もあります。
「KDDI au: そのほかの技術情報 > HTTP Requestヘッダ」には、以下の記述があります。
※2011年秋冬モデル以降の一部機種ではPCSVとEZブラウザのIPアドレス帯域は統合されますが、例えば、ユーザーエージェントを組み合わせることでブラウザを判別することができます。
また、同じページから参照されているユーザエージェントの「判定CGI(サンプル)」は、PCSVからの「成りすまし」に対して、誤判定します。
しかしながら、これらはあくまでもミクロの問題です。同じページには以下の記載があります。
EZ番号とは、EZweb契約ごとにユニークに付与されるIDです。例えば、ユーザーの判別などに利用することができます。
※IPアドレス/ユーザーエージェントでのフィルタ、ID/パスワード認証を併用するなど、サイト内容に応じた適切な方法でご利用ください。
かつては、同じページ内に「ユーザ認証に用いる場合には…」という記載があり、EZ番号による認証をキャリアとして認めているように読める文面でした(参考:「EZ番号に関する注意書きが変更された」)。それが「ユーザの判別」という曖昧な表現に変更され、かつ「ID/パスワード認証を併用する」という注記が追加されたことから、KDDIはEZ番号によるかんたんログインに対して保証を与えていないと私は解釈します。
しかし、大手著名サイトを含む多くのサイトがかんたんログインを実装していることもまた事実です。この影響を考慮し、KDDIはPCSVのIPアドレスを分けるという対処をしたのだと思います。この対応は妥当だったと私は考えます。
まとめ
au/KDDIの2011年秋冬モデルF001のPCSVを用いたかんたんログインなりすまし問題について説明しました。一時的に、多数のユーザに対する成りすまし可能な状態がありましたが、KDDIにより早期に対処され、現在では安全と思われます。しかし、この機に、かんたんログインが極めて危うい状況にあることをご認識いただき、かんたんログインを廃止することを強く推奨します。[PR]
「安全なWebアプリケーションの作り方」DRMフリーのPDFによる電子版もあります。
0 件のコメント:
コメントを投稿