May 29, 2019

ツリー型タブとマルチプルタブハンドラに脆弱性がありました

English Version

既にTwitter等でお知らせしていますが、ツリー型タブのバージョン2.0~3.0.13とマルチプルタブハンドラのバージョン2.0~3.0.6に脆弱性がありました。

  • 問題自体はツリー型タブ 3.0.14以降およびマルチプルタブハンドラ 3.0.7以降で修正済みです。
  • 自動更新を停止していたり、古いバージョンのFirefox用に古いTST・MTHを使用していたりすると、脆弱性を突かれる恐れがあります。更新またはアンインストールを強くお勧めします。

詳細な説明はGitHubのissueに日本語でも記載していますが、端的に言うと「他のアドオンと連携するために独自に提供していたAPIの仕様がガバガバだった」という事になります。

  • 通常、WebExtensionsベースのアドオンでは明示的に宣言されインストール時に許可された範囲の情報しか取得できない。タブの現在のタイトル、URL、アイコンもそのような情報の一種。
  • TSTやMTHは動作上どうしてもタブのタイトルやアイコンを知らなくてはいけないので、それらの権限を要求する旨宣言している。インストール時にもそのあたりの事が警告される。
  • TSTやMTHは、他のアドオンの求めに応じてツリーの情報や選択されたタブの情報を返したりプッシュ式に通知したりするためのAPIを提供している。このAPIを介して返される情報は、TSTやMTHが自身の権限に基づいてWebExtensions APIから得たtabs.Tabのオブジェクトに基づいて、それとの互換性を保つようにしていたため、その中に無条件でタブのタイトル、URL、アイコン、およびプライベートウィンドウのタブの情報が含まれていた。これらの情報が、本来は取得するために特別な権限が必要な物であるという事を失念していた
  • このAPIはbrowser.runtime.sendMessage()というWebExtensions APIを使って呼び出す物だが、browser.runtime.sendMessage()の呼び出しには特別な権限は要らない
  • よって、TSTやMTHがインストールされている環境では、どんな権限でインストールされたアドオンからでも、全く無警告に、そういった情報を参照できてしまうという状態だった。

一応、この「脆弱性」を使って悪さをするアドオンとしてこういう物が実際にある、というような報告はまだ受けていません。あくまで、作者が自主的に行った仕様の再チェックで脆弱性が見つかったという事になります。

が、「誰も気付かないような所、仕様の穴を突いたイリーガルな使い方をすると情報を盗み出せる」というような物ではなく、技術情報としてドキュメントも公開しているAPIを堂々と使って、WebExtensionsのアドオンごとの制限を突破して情報を取得できる、しかもその情報自体は実は2017年のバージョン2.0リリースの時から1年半以上もの間ずっと公知だったという、我ながら書いていて情けなくなるお粗末な状況なので、この脆弱性を利用した悪意あるアドオンが既に存在していても、全くおかしくはないと思っています。

ということで、もしそのようなアドオンを見つけた方がいらっしゃいましたら、お手数ですがどうかタレコミをお願いします。

折良く(?)、Mozillaのアドオンコミュニティの担当者の方からおすすめアドオンの件について連絡を頂いたので、ついでにこの件についても相談してみました。何か進展があったらまた告知すると思います。


それにしても、何故こんなにお粗末な事をやらかしてしまったのか。理由はいくつか考えられます。

まず1つは、XULアドオン時代の設計思想を引きずってしまっていたこと。

元々、XULアドオン時代にはFirefoxのアドオンはすべての情報にフルアクセスというのが当たり前でした。なので、TSTやMTHのAPIには、呼び出し元ごとに返す情報に差を付けないといけないという考えが全くありませんでした。聞かれた事はなんでも返していい、何故ならどうせ呼び出し元のアドオンだって、それらにアクセスしようと思えばいくらでもできるんだから。これがXULアドオン時代の考え方でした。

他方、WebExtensionsでは、各アドオンは事前に許可された範囲の情報しかアクセスできないので、ユーザーは各アドオンの権限だけを気にすれば良いという事になっています。この事ばかりが強く印象に残っていたことと、とにかくXUL版から機能を移植するという事にばかり気を取られていたために、アドオン同士の間ですらもアクセスできる情報の範囲に差があるという事が、頭の中からすっかり抜け落ちていたのだと思います。

「アドオン同士の権限に差がある」というWebExtensionsの世界に合わせるには、TSTやMTHのAPIにもその考え方を反映しないといけなかったんですね。自分のアドオンが正当な手順でWebExtensions APIから入手した情報は、相手のアドオンにとっても同様に正当な手順で入手できる情報だ、とは限らないのです。それを忘れて呼び出し元の求めに応じてなんでも返してしまっていたというのは、「内緒にするから教えて」と言って教えてもらった情報を、他人にホイホイ言いふらすようなものです。実に嘆かわしいです。

2つ目の理由は、permissionsで宣言する権限の影響範囲を正しく把握しきっていなかったこと。

tabsという権限の名前からはいかにも、タブに関する事なら何をするのにも、例えばタブの一覧を取得するのにすらも必須であるような印象を受けます。TSTやMTHのAPIを呼ぶには呼び出し側のアドオンがタブのIDを知っている必要があり、タブのIDを知っているなら当然tabsの権限も持っているはず、ならタブのプロパティ全部渡しても問題無いはず(どうせ呼び出し側のアドオンが自分でも同じ情報を取得できるんだから)。というのが、これらのAPIを作った時点での自分の認識だったのだと思います。

しかし実際には、tabs.query()などのWebExtensions APIはtabsの権限無しでも呼ぶ事ができます。tabs/activeTabの権限の有無は、タブの一覧を取得できるかどうかではなく、返されるタブの情報にタイトルやURLなどのセンシティブな情報が含まれるかどうかという点にだけ影響します。TSTやMTHをWebExtensionsで実装するにあたって、まだWebExtensionsの仕様への理解が浅かったかなり初期の時点でtabsの権限を設定したきりだったために、この勘違いがずっと正されないまま今に至ってしまっていたのでしょう。他のアドオンを作る時にも、自分はひょっとしたらtabsの権限が不要なのに要求してしまっているという例があるかもしれません。

今回のことから得られた教訓は、以下のようにまとめることができると思います。

  • それぞれの権限が何を可能にするのか、その権限が無いと何ができなくなるのかを、ちゃんと理解しておく。不要な権限は要求しないようにして、常に必要最小限の権限だけをpermissionsには列挙する
  • WebExtensions APIから自分の権限で取得したオブジェクトをそのまま使い回して、他のアドオン向けのメッセージに含めてはいけない。必ず、センシティブでない事が分かっている情報だけをホワイトリスト形式で抽出して、スクラッチでメッセージを組み立てること。

僕のように「他のアドオン向けのAPI」を提供するアドオンを作ろうと思っている方は、どうか僕と同じ過ちを犯さないように、他山の石として下さい……

エントリを編集します。

wikieditish message: Ready to edit this entry.











拡張機能