株式会社クリアコード > ククログ

ククログ


設定変更時にのみ起こる問題の、原因となっている設定項目を特定する

FirefoxやThunderbirdは、MCD(別名:AutoConfig)ポリシー設定を使ってある程度の設定を集中管理できます。集中管理可能な設定項目の情報は当社のサポート業務で把握している頻出設定の一覧Mozilla公式のポリシーテンプレートの説明などで調べることができ、実際の運用では、これらの資料で得た情報に基づいて書き上げた設定ファイルをFirefox(Thunderbird)に読み込ませることになります。

ただ、それですんなりいけばよいのですが、時には単純な記述ミスや、記載した設定の未知の特性の影響などによって、想定外の問題が起こる場合も度々あります。そのような場面で、多数ある設定の中から問題の原因箇所を特定するのはなかなか大変です。項目が多い場合、しらみつぶしに調査していては時間がいくらあっても足りません。

このような場面では、後退バグの発生原因となったコミットを特定する際にも使用した二分探索が有用です。

設定ファイルを対象とした二分探索の基本的な手順は、以下のようになります。

  1. 設定ファイルを前半と後半に分け、どちらか一方、例えば前半を削除する。
  2. その設定ファイルをFirefox(Thundebrird)に読み込ませ、動作を確認する。
    • 問題が再現しないようであれば、削除した部分(前半)のどこかに問題があると見なす。
      削除した部分(前半)を元に戻し、削除する範囲と残す範囲を入れ換える。
    • 問題が再現するようであれば、現在残っている部分(後半)のどこかに問題があると見なす。
  3. 残った部分を対象として、同じ操作を繰り返す。

二分探索では、しらみつぶしに調べるよりもはるかに少ない試行回数で原因箇所を特定できます。しかしながら、やり方を誤ると、問題が無い箇所を問題の原因と誤認してしまう事もあり得ます。この記事では、Firefoxの集中管理用設定ファイルを対象に二分探索を行う際のよくある注意点を紹介します。

ファイルの形式を問わない注意点

Virtual Storeの影響の排除

MCDの場合もポリシー設定の場合も、Windowsにおいて集中管理用の設定ファイルを直接編集する場合には、Virtual Storeの影響を受けないように気をつける必要があります。

現在のWindowsでは C:\Program Files 配下などの位置にファイルを保存しようとすると管理者権限での認証を求められますが、古いWindows向けアプリケーションにはそのような認証処理に非対応の物があります。そこでWindowsは、認証を行えなかった場合には暫定的に C:\Users\username 配下にファイルを保存しておき、以後 C:\Program Files 配下のファイルにそのユーザーの権限でアクセスしようとした場合は、代わりに C:\Users\username 配下に保存した方のファイルの内容が返却する、という動作を行います。この機能が「Virtual Store」です。Firefox・Thunderbirdの集中管理用設定ファイルは、一般ユーザーが勝手に内容を変更してしまうことがないよう、変更に管理者権限が必要な位置に置かれますので、不用意に編集しようとするとVirtual Storeの影響を受けてしまうことがあります。

Virtual Storeの影響を受けないようにするためには、「EmEditor」のように管理者権限での認証に対応したテキストエディターを使うか、もしくは、以下の手順で操作する必要があります。

  1. 設定ファイルを一旦デスクトップにコピーする。
  2. デスクトップにコピーしたファイルを編集する。
  3. ファイルを上書き保存する。
  4. 編集後のファイルをC:\Program Files 配下の元の位置に上書きコピーする。
ファイルのエンコーディングの維持

MCD用設定ファイルもpolicies.jsonも、エンコーディング形式は「BOM無しのUTF-8(リトルエンディアン)」が正式です。しかしながら、Windowsのバージョンが古いと、「メモ帳」を使ってファイルを編集した場合にBOMが付与されてしまったり、意図せずエンコーディングが変更されてしまったり、といったトラブルが起こり得ます。この事が原因で、編集後のファイル全体がエラーとなり、まったく動作しない状態となってしまう場合もあります。

このようなトラブルを避けるためにも、集中管理用設定ファイルの編集には、先にも名前を挙げた「EmEditor」のように「BOMの有無やテキスト保存時のエンコーディングを自由に指定でき、また、ファイルの上書き保存時には元のエンコーディングを可能な限り維持する」性質を持つテキストエディターを使用する事を強くお勧めします。

MCD(AutoConfig)の設定ファイルで二分探索を実施する場合の注意

MCD用設定ファイルはJavaScript形式なので、単純な記述ミスであればeslintで文法エラーを検出できます。

文法エラーでない原因で起こる問題を二分探索で探る際にも、その過程での文法エラーの発生には気をつける必要があります。例えば、以下のように条件分岐を伴う設定が記述されている場合:

if (getenv('USERDOMAIN' == '...') {
  lockPref('...', true);
  lockPref('...', false);
  lockPref('...', 0);
}

このような箇所が二分探索の境界上にあると、

if (getenv('USERDOMAIN' == '...') {
  lockPref('...', true);

// ここでファイルが終了しており、開かれた括弧が
// 閉じられないままになっている

// ここでファイルが始まっており、開き括弧が無いまま
// 閉じ括弧だけがある状態になっている

  lockPref('...', 0);
}

のように文法的に不正な状態が発生してしまうことがあります。二分探索の境界は、このような箇所を避けて決めるように気をつけましょう。

ポリシー設定の設定ファイル(policies.json)で二分探索を実施する場合の注意

ポリシー設定をGPOではなくpolicies.jsonで行う場合、policies.jsonは(JavaScriptではなく)JSON形式として妥当である必要があります。

例えば、以下のような内容のpolicies.jsonがあった場合:

{
  "policies": {
    "DisableAppUpdate": true,
    "ExtensionUpdate": false,
    "EnableTrackingProtection": {
      "Value": true,
      "Locked": true
    }
  }
}

以下のように単純に行で区切って二分探索すると、閉じ括弧が欠けているために文法エラーとなり、内容が読み込まれません。

{
  "policies": {
    "DisableAppUpdate": true,
    "ExtensionUpdate": false,
    "EnableTrackingProtection": {
      "Value": true,
{
  "policies": {
    "DisableAppUpdate": true,
    "ExtensionUpdate": false,

また、見落としやすい注意点として、いわゆる「ケツカンマ」の存在があります。設定項目にあたる部分だけを削除して

{
  "policies": {
    "DisableAppUpdate": true,
    "ExtensionUpdate": false,
  }
}

のように最後の項目の末尾に「,」が残ったままになっていると、これはJavaScriptの文法上はエラーにならないのですが、JSON形式としては文法エラーになります。このような箇所は必ず、

{
  "policies": {
    "DisableAppUpdate": true,
    "ExtensionUpdate": false
  }
}

のように、最後の項目の後に残った「,」を取り除いておく必要があります。

編集後のファイルがJSONとして妥当かどうかは、JSONLintで確認できます。policies.jsonを組織外に晒すことを避けたい場合は、npmパッケージのjsonlint-cliのようにオフラインで実行できる文法チェックツールを使うと、同等の検証を行えます。

まとめ

Firefox・Thundebirdの集中管理に使うMCD用設定ファイルとポリシー設定ファイルについて、問題発生時の原因を二分探索で調査する手順と、その注意点をご紹介しました。

この記事でご紹介した調査方法は多くの場合で有効ですが、残念ながら万能ではありません。設定項目の中には複数が組み合わさった場合にのみ問題が起こる物もあり、二分探索を実施しても「前半と後半それぞれだけで読み込んだら問題無いのに、全体を合わせると問題が起こる」というような不可解な状況が発生する場合があります。そのようなケースでは、ログと突き合わせての調査なども併用する必要があります。どうしても問題の原因を掴めないという場合には、当社の法人向け有償サポートがお役に立てるかもしれませんので、ぜひ一度お問い合わせください

タグ: Mozilla
2020-05-16

Firefox 74以降でのアドオンのサイドローディングの代替

Mozillaの公式なアナウンスにある通り、Firefox 74以降のバージョンではアドオンの「サイドローディング」ができなくなりました。この変更は次のESR版であるESR78にも影響するので、主に企業ユーザー向けの情報として、対策・代替運用の情報をご紹介します。

サイドローディングとは何? なぜ廃止されたの?

まず用語の説明をします。

「サイドローディング」とは、通常の一般的なインストール手順を経ずに、FirefoxやThunderbirdにアドオンをインストールする方法です。Norton Internet Securityなどのソフトウェアをインストールすると、自分でインストールした覚えがないのにFirefoxやGoogle ChromeにNorton Internet Securityとの連携用ツールがインストールされることがありますが、これがサイドローディングです。

一般ユーザーにとっては、サイドローディングはセキュリティ上の脅威やユーザー体験の劣化に繋がるリスクがあります。悪意あるアドオンがサイドローディングされると、機密情報や個人情報の漏洩に繋がりかねません。また、サイドローディングでインストールされたアドオンは一般ユーザー権限では削除できず、Firefoxのアドオンマネージャ上に「削除できないアドオン」として居座り続けることになります。無効化はできますが、それでも毎回の起動時に不要なファイルが多数読み込まれると、起動にかかる時間の増大は避けられません。これらが、Firefox 74で公式にサイドローディングが廃止されるに至った背景です。

ESRでのサイドローディング

先に紹介したMozillaの公式のアナウンスには、「Additionally, Firefox Extended Support Release (ESR) will continue to support sideloading as an extension installation method.(ESR版では引き続きサイドローディングが使えます)」と書かれています。企業ではアドオンを社内のセキュリティ施策の実現のために使っている事例があるなど、アドオンが業務と密接に関わることがあり、このような判断がなされたようです。

法人利用での目下の課題は、現在の所ESR78のベータ版や開発版ではサイドローディングを使った運用の検証ができないという点です。

サイドローディングの有効・無効の切り替えは現在の所ビルドオプションで行われており、更新チャンネルがESRと指定されている場合にON、そうでなければOFFになるという設計になっています。そのため、更新チャンネルがESRではない開発版やベータ版ではサイドローディングが無効化されたままとなります。ESR78でアドオンをサイドローディングさせた状態の運用を検証するためには、正式版リリースを待つか、ソースコードをダウンロードしてきてESR版として自分でビルドするしかありません*1

このような問題があることに加え、サイドローディングには、ESRであってもいつまで利用できるかは不透明であるという懸念があります。今の所、明確に「ESRでも廃止する」というアナウンスは出されていませんが、将来的には廃止される可能性がある機能と思っておいた方が安全でしょう。

将来のESRやESR78の検証段階ではアドオンをサイドローディングできなくなる事を前提に考えて、企業の情シスご担当の方は、今のうちにアドオンの管理はポリシー設定で行う運用に移行するのがおすすめです。

サイドローディングを使わずに、システム管理者がアドオンのインストール状況を管理する

Firefox内蔵のポリシー設定機能は順調に拡充が進み、企業でのアドオン運用でよく見られるパターンであれば、以下のようなポリシーでおおむね要求事項をカバーできるようになっています。

以下、運用上の各場面での設定例をご紹介します。

導入時

Firefoxの運用を開始する時点で上記の例に対応するポリシー設定は、以下のようになります。

{
  "policies": {
    "Extensions": {
      "Install": [
        "\\\\fileserver\\shared\\addon-x-1.0.xpi",
        "\\\\fileserver\\shared\\addon-y-1.0.xpi"
      ],
      "Locked":  [
        "addon-x@example.com",
        "addon-y@example.com"
      ]
    },
    "InstallAddonsPermission": {
      "Default": false
    },
    "BlockAboutAddons": true,
    "ExtensionUpdate": false
  }
}

この例では、アドオンのインストールパッケージがSambaサーバーの共有ディレクトリ上に置かれており、UNCパス \\fileserver\shared でファイルの位置を参照できる場合を想定しています。JSONファイル内ではバックスラッシュはエスケープ文字となるため、UNCパス内の区切り文字のバックスラッシュがすべて二重になっていることに注意して下さい。Fx Meta Installerを使ってXPIパッケージをローカルに配置するインストール方法を使っている場合や、何らかの資材管理ツールを使っている場合には、以下のように通常のローカルファイルパスを指定することもできます。

{
  "policies": {
    "Extensions": {
      "Install": [
        "C:\\distributed-files\\addon-x-1.0.xpi",
        "C:\\distributed-files\\addon-y-1.0.xpi"
      ],
      ...
    },
    ...
  }
}

Active Directoryのグループポリシーを使う場合、.admx形式のポリシーテンプレートをドメインコントローラに読み込ませます。ポリシーテンプレートの使い方は先日のDNS over HTTPSに関する解説記事で詳しく述べていますので、併せてご参照下さい。

また、macOSではdefaultsコマンドの書き込み対象plistファイルに/Library/Preferences/org.mozilla.firefoxを指定して、以下の要領で設定します。

$ PLIST=/Library/Preferences/org.mozilla.firefox
$ sudo defaults write $PLIST EnterprisePoliciesEnabled -bool TRUE
$ sudo defaults write $PLIST Extensions__Install -array /distributed-files/addon-x-1.0.xpi /distributed-files/addon-y-1.0.xpi
$ sudo defaults write $PLIST Extensions__Locked -array addon-x@example.com addon-y@example.com
$ sudo defaults write $PLIST InstallAddonsPermission__Default -bool FALSE
$ sudo defaults write $PLIST BlockAboutAddons -bool TRUE
$ sudo defaults write $PLIST ExtensionUpdate -bool FALSE
アドオンの更新

Firefoxは、ポリシー設定のExtensions.Install似記述されたURLまたはパスが変更されていれば、そのアドオンを再インストールするようになっています。ファイル名にバージョン番号が含まれていれば、以下のように設定を更新するだけで、次回起動時にアドオンが更新される結果となります。

{
  "policies": {
    "Extensions": {
      "Install": [
        "\\\\fileserver\\shared\\addon-x-1.1.xpi",
        "\\\\fileserver\\shared\\addon-y-2.0.xpi"
      ],
      ...
    },
    ...
  }
}

言い換えると、このように管理者側でアドオンを更新することを考慮すると、アドオンのインストールパッケージはファイル名にあらかじめバージョン番号を含めた状態にして設置する必要があるということになります。

macOSでdefaultsコマンドを使用する場合は、配列の要素を削除する機能が無いため、以下の要領で配列の値すべてを置き換える必要があります。

$ sudo defaults write $PLIST Extensions__Install -array /distributed-files/addon-x-1.1.xpi /distributed-files/addon-y-2.0.xpi
アドオンの削除

アドオンの運用を終了する場合は、Extensions.InstallExtensions.Lockedから項目を削除し、Extensions.Uninstallに削除対象のアドオンのIDを列挙します。

{
  "policies": {
    "Extensions": {
      "Install": [
      ],
      "Uninstall":  [
        "addon-x@example.com",
        "addon-y@example.com"
      ],
      "Locked": [
      ]
    },
    ...
  }
}

macOSでdefaultsコマンドを使用する場合の注意事項は前項と同様です。すべての項目を削除して配列を空にする場合は、-arrayを指定して値を省略します。

$ sudo defaults write $PLIST Extensions__Install -array
$ sudo defaults write $PLIST Extensions__Uninstall -array addon-x@example.com addon-y@example.com
$ sudo defaults write $PLIST Extensions__Locked -array

まとめ

Firefox 74でのアドオンのサイドローディング廃止と、法人運用でのその影響、および、サイドローディングを使わずにポリシー設定でアドオンを運用する手順についてご紹介しました。

当社では、お客さまからの技術的なご質問・ご依頼に有償にて対応するFirefoxサポートサービスを提供しています。企業内でのFirefoxの運用でお困りの情シスご担当者さまやベンダーさまは、お問い合わせフォームよりお問い合わせください。

*1 アドオンが認識された状態での動作を検証するだけならユーザーインストールでも構いません。ここでは「Firefoxを初めて起動した時点でアドオンが読み込まれていること」のように、サイドローディングの性質が重要となる場面の検証を想定しています。

タグ: Mozilla
2020-04-24

Gecko Embedded 68ESR対応

はじめに

クリアコードでは Gecko(Firefox)を組み込み機器向けに移植する取り組みを行っています。
ククログ記事を長らく書いていませんでしたが、68ESRに移植する取り組みを行っていましたので、紹介します。

この対応にあたっては OSSystems/meta-browser というYoctoレイヤをフォークして作業を行っていますが、対応が落ちついたバージョンについてはアップストリーム(OSSystems/meta-browser)に成果をフィードバックしています。68ESR対応では、Firefoxをビルドするためのコンパイラがgccからclangに変更となったため、meta-clangというclangを提供するレイヤーを新たに使う必要がありました。
また、68ESRではAArch64のJITの対応が進み、JavaScriptの実行速度が大幅に高速化しました。

meta-clangへの依存

60ESRから68ESRに更新するのにあたって、Firefoxをビルドするためのコンパイラがgccからclangに変更となりました。
clangをビルドのツールチェインとして使用するYoctoのレシピが公開されていたため、これを使うことになりました。
clangはLLVMをベースのインフラとして使用するコンパイラです。LLVMはモジュール化が進められており、再利用が可能なコンポーネントを目指して開発が進められています。

また、C++のランタイムについては、gcc由来のものを使うビルド設定でもビルドを確認しています。

RenesasのRZ/G2Eのリファレンスボード(ek874)では、以下の設定をlocal.confに入れることでgcc由来のC++のランタイムライブラリ(libstdc++)をリンクすることになります。*1

TARGET_CXXFLAGS_remove_toolchain-clang = " --stdlib=libc++"
TUNE_CCARGS_remove_toolchain-clang = " --rtlib=compiler-rt --unwindlib=libunwind --stdlib=libc++"
TUNE_FEATURES_remove_toolchain-clang = "cortexa57-cortexa53"

これらの設定を入れない場合はclang由来のC++ランタイムライブラリ(libc++)がリンクされることになります。

68ESRへのバージョンアップ

Geckoのベースバージョンを60ESRから68ESRに上げるにあたって、障害となるのはmeta-clangへの依存の組み込みでした。
この問題に関してはmeta-clangを使うことによりクリアできました。

また、組み込みGeckoではWayland/EGLの問題に度々直面してきました。
これらの問題に対処するためクリアコードでは、問題を見つけたら開発元で直す開発プロセスを実行しており、
Gecko 60ESR時点で見つかった問題に対応するパッチを開発元に報告できるものは最大限報告をしました。
このため、60ESRから68ESRにGeckoのベースバージョンを上げる時に組み込みGeckoで当てているパッチの量を減らすことができました。

当プロジェクトが作成した以下のパッチは68ESR時点では取り込まれています。

組み込みGeckoが使用しているGeckoのYoctoレシピの開発元で当てているWayland、EGLのパッチは4個まで減っています

現在のステータス

前回からの改善点は以下の通りです。

  • AArch64向けのJavaScriptのJITが強化され、JavaScriptの実行速度が高速化された
  • e10sが有効化され、APZによるタッチイベントが有効化された
  • e10s有効化時にEGLを有効化するとContentプロセスがSEGVする問題が解消された
  • Stylo(Quantum CSS)がデフォルト有効化された

現状では、以下の制限があります。

  • 60ESRでは効いていたGLスクリーンバッファが効かず、Wayland/EGL環境ではWebGLの性能が落ちている。そのためフレームレートが30fps近辺をウロウロする。

また、68ESRでは以下の機能が廃止されました。

  • 68ESRではCanvasのハードウェアアクセラレーション

この廃止に至った事情は以下が詳しいです。

メンテナンスコストを勘案し、ハードウェアアクセラレーションが必要なほど性能を要求するコンテンツについてはWebGLの使用を推奨するというMozillaの公式見解が出されています。

まとめ

GeckoEmbeddedプロジェクトのESR68の状況について紹介しました。
ESR68対応がひと段落しているものの、マイナーバージョンアップ対応をどのように対処するかなどまだまだ手が足りていない状況です。
ぜひ当プロジェクトに参加して頂ければ幸いです。

*1 https://github.com/webdino/meta-browser/wiki/Build-RZ-G2#localconf-%E3%81%AE%E7%B7%A8%E9%9B%86

タグ: Mozilla
2020-04-22

Firefoxでデフォルト有効化されるかもしれないDNS over HTTPSへの企業での対応について

昨日、Firefoxの米国エリアユーザーに対して段階的に「DNS over HTTPS」の有効化が反映されていくことになった、という話がニュースになっていました。

DNS over HTTPSとは?

今までの名前解決との違い

DNSとは、www.clear-code.comのようなドメイン名の文字列を153.126.132.63のようなIPアドレスに解決する(名前解決をする)という、インターネットにおけるかなり根幹の部分を支えている仕組みです。

この問い合わせ・応答の通信は特に暗号化も認証もなされていないため、問い合わせ内容の盗聴や応答の偽装が技術的には可能となっています。身近な場面では、空港や飲食店などのパブリックWi-Fiでそのような攻撃を受ける恐れがあるほか、地域によっては政府主導で盗聴・検閲が行われているケースもあるといいます。DNS over HTTPSは、このような脅威からユーザーを守る技術であるとされています。

ただし「DNS over HTTPSであれば何もかもが安全になる」というわけではないことに注意が必要です。DNS over HTTPSで安全になるのは全体の中のごく一部のやり取りのみで、それ以外の部分については別の技術的手段での保護が依然として必要です。また、組織内のみのドメインが名前解決できなくなるようなトラブルや、CDN*1の性能が発揮されないといった問題が起こる場合もあります。

具体的にDNS over HTTPSによって何が守られて何が守られないのかについては、ISP*2であるIIJの技術者向けブログの以下の記事に詳しい解説がありますので、ぜひご参照下さい。

FirefoxでのDNS over HTTPS

Firefoxはセキュリティやプライバシーの保護を理由として、DNS over HTTPSを推進していくことを以前から発表しています。今回行われたのは「米国地域内のユーザーに対して、DNS over HTTPSをデフォルト有効にする」という変更でした。

Firefox上でDNS over HTTPSを使用する場合の注意点・無効化の方法などは、以下の公式のサポート情報に記載があります。

企業運用においてFirefoxのDNS over HTTPSを強制的に無効化するには

Firefoxを企業内で運用する場合、現時点で直接的に影響を受けるのは米国地域内の拠点だけということになります。しかし、今後DNS over HTTPSが全世界で有効化されていく可能性はありますし、また、現時点でもユーザーが任意に機能を有効化できます。使われると企業内のセキュリティポリシーを守れない、などのさまざまな理由から、社内ではDNS over HTTPSを使わせたくないということもあるでしょう。

そのような場合、以下の方法でDNS over HTTPSを無効に固定する(ユーザーが任意に有効化できなくする)ことができます。

Windows Server 2008以降のバージョンでActive Directoryによるドメイン管理が行われている場合
  1. .admx形式のグループポリシーテンプレートと言語リソースをダウンロードする。ここでは policy_templates_v1.13 をダウンロードしたと仮定する。
  2. ダウンロードしたファイルの名前を変更し、末尾に.zipを付ける。
  3. ファイルをZIPアーカイブとして展開し、windows フォルダ内のすべてのファイルを、ドメインコントローラの C:\Windows\SYSVOL\domain\Policies\PolicyDefinitions に設置する。
  4. グループポリシーの管理画面を開き*3、「コンピューターの構成」の「ポリシー」→「管理用テンプレート」→「Mozilla」→「Firefox」で「Configure DNS Over HTTPS」をダブルクリックする。
  5. ポリシーを「有効」にし、以下の通り設定する。
    • 「Enable DNS over HTTPS.」のチェックを外す。
    • 「Don't allow DNS over HTTPS preferences to be changed.」のチェックを入れる。

このように設定しておくことで、そのドメインに参加しているWindows端末上で動作するFirefoxでは常にDNS over HTTPSが無効となります。

macOSの場合
  1. 端末を開く。

  2. 以下の3つのコマンド列を順番に実行する。

    sudo defaults write /Library/Preferences/org.mozilla.firefox EnterprisePoliciesEnabled -bool TRUE 
    sudo defaults write /Library/Preferences/org.mozilla.firefox DNSOverHTTPS__Enabled -bool FALSE 
    sudo defaults write /Library/Preferences/org.mozilla.firefox DNSOverHTTPS__Locked -bool TRUE 
    

このように設定しておくことで、そのマシン上で動作するFirefoxでは常にDNS over HTTPSが無効となります。

それ以外の場合(Windows、Linux)
  1. Firefoxのインストール先(Firefoxの実行ファイルがあるフォルダ)に distribution という名前でフォルダを作成する。

  2. 以下の内容のプレーンテキストファイルを作成し、policies.jsonという名前で1のフォルダ内に設置する。

    {
      "policies": {
        "DNSOverHTTPS": {
          "Enabled": false,
          "Locked": true
        }
      }
    }
    

このように設定しておくことで、その位置にインストールされているFirefoxでは常にDNS over HTTPSが無効となります。

この方法は、Active Directoryを運用していない場合や、シンクライアント端末からWindows Serverにリモートデスクトップ接続してFirefoxを使用する場合などに有用でしょう。

Canary Domainを利用する方法

ポリシー設定を使う方法とは別のやり方として、Canary Domainを使用する方法があります。具体的には、use-application-dns.net について NXDOMAIN を返すようにそのネットワーク内のDNSを設定しておくことにより、Firefoxはそのことを検出し、自動的にDNS over HTTPSを使用しなくなります。

これについての詳しい解説は、以下の記事をご参照ください。

社外に持ち出して使用することがある端末(ラップトップPCなど)が存在していて、社内ではDNS over HTTPSを無効化したいが、社外ネットワークでの利用に関しては特に制御したくない、という場合には特にこの方法が有用でしょう。

まとめ

DNS over HTTPSの概要と、ポリシー設定等を使って企業内でFirefoxのDNS over HTTPS動作を常に無効化する方法をご紹介しました。

当社では、お客さまからの技術的なご質問・ご依頼に有償にて対応するFirefoxサポートサービスを提供しています。企業内でのFirefoxの運用でお困りの情シスご担当者さまやベンダーさまは、お問い合わせフォームよりお問い合わせください。

*1 Content Delivery Network。動画などのネットワーク転送負荷が高いデータについて、名前解決時にホストをネットワーク的な距離が近いホストに解決することで、ネットワーク負荷を下げたりデータ転送にかかる時間を短縮したりするための仕組み。

*2 Internet Service Provider。インターネット接続事業者。

*3 Windows Server 2008では「Active Directory ユーザーとコンピュータ」を開き、ドメイン名を右クリックし「プロパティ」をクリックして、「グループポリシー」タブで「編集」ボタンをクリックする。Windows Server 2012では「グループ ポリシーの管理」を開いて「Default Domain Policy」を右クリックし「編集」を選択する。

タグ: Mozilla
2020-02-27

FirefoxでInternet Explorerのwindow.open()周りの挙動を再現する

日本におけるFirefoxの法人利用の代表的なニーズは「Internet Explorer向けに作られた古いWebベースの社内システムがあるためにIEを捨てられず、社外のWebを見に行くためにFirefoxを使いたい」というものです。しかし、それとは逆のパターンとして、「IE向けに作られたWebベースのシステムをFirefoxで使いたい」という場面もあります。後者の場合にはIEとFirefoxの細かな挙動の違いが問題となることがあり、window.open() でウィンドウを開くときの挙動の違いもその一つです。

名前付きの子ウィンドウ(タブ)の挙動の違い

window.open() はJavaScriptから利用できるブラウザの機能(いわゆるDOM0)で、子ウィンドウ(タブ)を開く物です。第2引数には「子ウィンドウの名前」を指定することができ、この方法を使って名前を付けて開かれた子ウィンドウ(タブ)は、<a target="ウィンドウ名" href="..."> のようにtarget属性を明示したリンクの読み込み先や、window.open() で同じウィンドウ名を指定した場合の読み込み先として再利用されることになります。

Internet Explorerでは、このような場面で以下のような挙動を取ります。

  • すでにその名前の子ウィンドウ(タブ)が開かれていた場合、とにかくそれを読み込み先として使う。
  • 読み込み先の子ウィンドウが最小化状態であれば、通常の状態に復帰させる。他のウィンドウの背後に隠れている場合であれば、最前面に持ってくる。

他方、Firefoxでは同じ場面で以下のような挙動を取ります。

  • 子ウィンドウはそれぞれのタブに対して個別に管理される。2つのタブそれぞれで子ウィンドウを名前を指定して開いた場合、それぞれのタブに対して別々の子ウィンドウが開かれる。その後のウィンドウ名を指定した読み込みも同様に取り扱われる。
    • →IEの挙動を前提に作られたWebアプリだと、無駄にたくさん子ウィンドウが開かれてしまう。
  • 読み込み先の子ウィンドウが最小化状態や他のウィンドウの背後に隠れている場合でも、そのままの状態で読み込みを行う。
    • →IEの挙動を前提に作られたWebアプリだと、「リンクやボタンをクリックしても(最小化された、または背後にあるウィンドウの中に読み込まれる場合があり)結果を画面上で確認できないという事が起こる。

Firefoxアドオンでの解決

Webアプリとしては、このような挙動の違いを吸収したり、Firefoxのような挙動でも問題が起こらないようにしたりと対策を取れればそれに越したことはありません。しかし、様々な事情からそれができない場合もあります。

そのようなお客さまからのご相談を受けて、Firefox上でIEの上記の挙動を再現するためのアドオンを開発しました。以下のリンクからインストールできます。

  • Merge Named Browser Windows:ウィンドウ名を指定して子ウィンドウ(タブ)が開かれた場合に、親ウィンドウ(タブ)を問わずその名前の既存のタブを探して閉じ、特定の名前のタブが1つだけ開かれているという状態を維持する。
  • Unminimize Browser Window On Load:最小化状態や背面にあるウィンドウにコンテンツが読み込まれた場合に、ウィンドウを復帰させフォーカスを与える。

主にセキュリティ向上のために、現代のWebブラウザはウィンドウ(タブ)間での情報の分離を徹底する方向で進化しています。また、迷惑な広告やいわゆるブラクラの類にユーザーが煩わされる事が無いよう、コンテンツ側からの操作によるウィンドウのフォーカス制御も制限されるようになっています。それらの変化は一般的なWebサイトを閲覧するユーザーにとって好ましいものですが、特定のWebアプリの使用頻度が高くなる法人利用では却って困った結果になる事もあります。

そのような特殊な場面での暫定的な対処のための方法として、一般的なWebアプリよりも強力な権限が与えられているアドオン(拡張機能)は有用な選択肢となる場合があります。Firefoxの法人利用で似たような事にお悩みの企業担当者さまがいらっしゃいましたら、お問い合わせフォームより是非ご連絡下さい。

タグ: Mozilla
2019-11-26

フリーソフトウェアの法人向けサポートの一環で行った開発元へのフィードバックの事例紹介

当社の法人向けサポートサービスでは、企業のお客様がフリーソフトウェアを使われていて遭遇されたトラブルの解決や原因究明、文書化されていない技術情報の調査などを有償にて行っています。「特殊な労働力を提供してお客様の役に立ち、その対価としてお金を頂く」ということで、ビジネスモデルとしてはシンプルです。

ところで、当社の理念は「自由と稼ぐの両立」です。前述のビジネスモデルから「稼ぐ」は容易に読み取れますが、これがどのように「自由」に繋がっているかは見えにくいかもしれません。

まず単純に、「ユーザーが増える事が自由なソフトウェアの推進になる」という事が言えます。それは「そのソフトウェアを使うと開発チームに広告収入が入る」といった直接的な還元に限りません。例えば、そのソフトウェアのユーザーが増えると、業界内でのそのソフトウェアの影響力が増すので、プロプライエタリな製品にとってはそのデータ形式やプロトコルを無視しにくくなり、ユーザーが特定の製品に囲い込まれるリスクが低減する、という効果が期待できるでしょう。

また、こちらがこの記事の本題なのですが、このビジネスの中で実際の使用環境で見つかった不具合を報告したり、実際の使用環境でのニーズを汲み取った提案をしたりという形で、そのソフトウェアの改善に寄与できます

ということで、以下、Mozilla製品の法人向けサポート由来のフィードバックの事例を4つご紹介します。

Bug 1540943 - Broken message body on forwarding a mail including invalid character(Mozilla Thunderbird)

これは、メールの本文にエンコーディング上不正な文字が含まれていると転送メールの本文が文字化けしてしまうという問題です。法人利用では様々なメールが頻繁に・大量にやり取りされるため、このような「普通は起こらないエッジケース」が起こる事があり、また、それがビジネス上の支障になってしまう場合もあります。この現象に遭遇されたお客さまの場合、取引先からのメールを転送しようとすると文字化けしてしまうという事でお困りでした。

原因と回避策を調査した結果、本文として転送する場合には発生を避けられない問題である事が分かったため、お客さまには「添付として転送」などの別の操作を使って回避して頂く事をお薦めし、開発元には上記のBugの通り、その時点で判明していた発生条件などの情報を報告しました。

その後、開発者の方の目に留めて頂き調査が進んで、最終的にはソースコード中の1行をピンポイントで修正(呼び出す関数を変更)して問題を解消するパッチが投入されました。変更点が少なかった事から、この修正はThunderbird 60のメンテナンスリリースにも反映される結果となっています。

Bug 1563665 - Replied mails are not marked as "replied" if the folder has a comma (,) in its substance file name(Mozilla Thunderbird)

これは、メールフォルダに対応するローカルディスク上のファイルの名前に , (半角コンマ)が含まれているとそのフォルダ内のメールに返信などの操作をしても「返信済み」のようなマークが付かないという問題です。Thunderbirdではメールフォルダ1つがディスク上の1ファイルとなるmbox形式が初期設定となっており、ファイル名はフォルダ名そのままではなくMUTF-7という特殊なエンコーディング方式で英数字に変換されているのですが、台北 のような特定の文字列で変換結果が &U,BTFw- となり , が含まれる事になって、全く予想もしていなかった所でこの不具合に遭遇してしまう場合があるという状況でした。

お客さまには、MUTF-7でのエンコーディング結果に , が含まれないようにフォルダ名を工夫するという回避策をご案内していますが、どんな文字列がエンコーディング後にこのパターンになるのかについては事前の予想が難しいため、残念ながら万全とは言えない回答となってしまいました。

この問題は原因そのものは判明したものの、古くからある設計上の判断に起因する問題ということで、どのような方向で対処するのが妥当かという技術的判断の落とし所が見つかるまで、修正にはまだしばらく時間がかかりそうです。

Bug 1569089 - The "-version" ("-v") command line option doesn't report version information when using cmd.exe(Mozilla Firefox)

これは、Firefoxの起動オプションの一部が特定の状況下で動作しなくなっているという問題です。Firefoxは実は firefox.exe -v という風に -v オプションを指定して起動すると一般的なコマンドと同様にバージョン情報を文字列として出力するようになっており、これを使って現在インストール済みのFirefoxのバージョンを確認するという運用を取られているお客さまがいらっしゃったのですが、FirefoxをESR68に更新するとバージョン情報が出力されなくなったために運用に支障が生じている、という事でお問い合わせを頂きました。

調査の結果、Bugに記載しているとおりこの問題そのものは回避が不可能という事が分かったため、Firefoxのバージョンを調べるには何かしら別の方法*1を使わなくてはならない旨をお客さまにはお伝えしました。

-v はあまり使われる事の無さそうなオプションで、我々も正直な所、今回の調査を行うまでオプションの存在自体を把握していませんでした。しかし、報告したBugは優先度P2 (クリティカルな問題に対して付けられる P1 の次に高い優先度)と設定されています。本稿執筆時点では未解決ですが、もしかしたら案外早く修正される事になるかもしれません。

Add managed storage support (Duplicate Tabs Closer)

こちらはFirefox本体ではなくアドオンへの改善提案です。「Duplicate Tabs Closer」は同じURLのタブを重複して開く事を制限するアドオンで、重複の検出基準や検出時の挙動について様々な設定ができるようになっています。しかしながら、それらの設定値はローカルストレージ領域を使って保存されており、システム管理者の側では設定を制御できません。ですので、法人利用であらかじめ動作を決めておきたい場合、アドオンのソースコードを編集して組み込みの初期設定を変更する必要があります。

お問い合わせを頂いたお客さまの導入環境向けにそのように改造する事自体は容易ですが、提供開始後にアドオンが更新されたらそれへの追従の必要が生じます。また、その後同様のニーズをお持ちのお客さまから相談を頂く度に改造版を作る必要もあります。

その一方、Firefoxのアドオン向けAPIにはManaged Storageという機能があり、専用のファイルもしくはポリシー設定用の policies.json に書いた設定をアドオン側で読み取る事ができます。もしDuplicate Tabs CloserがManaged Storageに対応していれば、アドオンのソースコードを毎回編集する必要はありません。

以上の事を踏まえて、Managed Storageから設定値を読み込んで反映するという動作を追加する変更を提案した物が、上記のプルリクエストです。こちらは作者の方のご理解を得る事ができ、無事にマージして頂けました。

法人向けサポートからアップストリームへフィードバックする事の意義

アップストリームへのフィードバックは開発の現場に直接関わる事に等しいため、的確なフィードバックには様々な知識が必要になってきます。FirefoxやThunderbirdのように「ソフトウェア開発者でないエンドユーザーも使う物」ではこの点がネックとなりがちなためか、ユーザー自身によってなされた報告にはどうしても、不正確な報告や発生条件の絞り込みが不足した報告が散見されます。また、多くの日本人にとっては英語自体がハードルとなって余計にフィードバックしにくいという問題もあります。当社が法人サポートの中で行っているフィードバックは、これらの点を補ってフリーソフトウェアを推進していく物と言えます。

ビジネス的観点においても、アップストリームへのフィードバックには意義があります。問題点をそのプロダクトの開発元にフィードバックしないで手元での回避だけを行っていると、プロダクトの更新や変更でその回避策が取れなくなる恐れがあり、将来的なリスク要因になります。早め早めにフィードバックしてプロダクト本体側で問題を解決する事によって、その種のリスクが低減され、より安定して運用できるようになる事が期待できます*2。安物買いの銭失いにならなければ、それはサービスの付加価値と言えます。

そうしてプロダクト自体の品質が高まって企業で採用しやすくなると、法人向けサポートの需要の拡大にも期待できます。また、当社内でフィードバック対象のプロダクトへの理解が深まり知見が増えれば、それだけサービスの品質が向上します。

開発プロジェクトにとっても、ユーザーとなるお客さまにとっても、サポートを提供する当社にとっても利益になるという事で、これは「自由と稼ぐの両立」という理念の1つの実践例となっているわけです。

まとめ

以上、当社が法人向けサポートサービスを通じて行ったフィードバックの例を挙げて、会社の理念をどのように実践しているかをご紹介しました。

当社の法人向けサポート事業はいわゆるSI業界の周辺にあり、直接の取引先やその先のお客さまには「お堅い」業界の会社さまも多くあります。そのような業界はオープンさ・自由さと縁遠いという印象を持つ方が多いかもしれませんが、実際にはその内側ではフリーソフトウェアが使われていることは珍しくありません。やり方次第ではその領域のビジネスと自由なソフトウェアの推進を同時に行えるという事例の1つとして、参考にして頂ければ幸いです。

また、業務上でのフリーソフトウェアの使用においてトラブルに遭遇されていて、フリーソフトウェア製品やプロジェクト側の知識の不足でお困りの企業の担当者さまがいらっしゃいましたら、お問い合わせフォームよりお問い合わせ下さい。

*1 Windowsのレジストリの情報を参照する方法が一般的です。

*2 理論上、そうして問題が解消されていった先には全く仕事が無くなるという未来がいずれ訪れる事になりますが、実際にはプロダクトもユーザー側の要件も変化し続けるため、そのような未来がすぐに訪れるという事は、幸か不幸かまだ無さそうです。

2019-09-09

Firefox ESR60からESR68に移行するには

2019年7月9日に、Firefox ESR (Extended Support Release) の最新バージョンとなるFirefox 68.0esrがリリースされました。

この記事では、最新版への移行を検討されている企業ユーザーの皆様に向けて、ESR68に移行するための主要なスケジュールと、ESR60→ESR68の主な変更点について解説します。

移行スケジュール

ESR68に関連する主だったタイムラインを表として整理します(公式スケジュール表より整理・抜粋)

ESR60ESR68メモ
2019年05月21日 (火)Firefox 60.7 ESR-
2019年07月09日 (火)Firefox 60.8 ESRFirefox 68.0 ESRFirefox 68ESR正式リリース
2019年09月03日 (火)Firefox 60.9 ESRFirefox 60.1 ESR
2019年10月22日 (火)-Firefox 68.2 ESRFirefox 60ESRサポート終了
2019年12月10日 (火)-Firefox 68.3 ESR

この表の最も重要なポイントは 2019年10月22日のESR68.2のリリース です。この日をもって、現行バージョンのESR60のサポートが終了するので、これが実質的なバージョンアップのデッドラインとなります。運用を担当されている方は、この日までに検証を終えて、各端末上でアップデートを実行できるようにする必要があります。

なお、日付はいずれも太平洋標準時基準(PST)です。日本時間では、おおむね当日の深夜帯から翌早朝にかけてのリリースとなります。この時差の問題は、「リリース日に合わせて計画を立てたが、肝心のバージョンが当日の営業時間内にリリースされなかった」というミスにつながるので、段取りを組み立てる際に頭にとめておく必要があります。

ESR68の主なトピック

ここからは、ESR60からESR68で何が変わったのかという本題に移ります。変更箇所そのものは非常に膨大で、数万単位のコミットが加えられています。弊社の標準的なガイダンスでは、そこから要点を絞って約25項目を議論します。この記事では、そこから組織運用上、影響の大きい11項目をトピック別にお伝えします。

Symantec社の証明書がすべて失効します

ESR68からSymantecが発行した証明書は「信頼されない証明書」とみなされるようになります。具体的には、HTTPSでアクセスしようとした場合、警告画面が出現して、先に進めないようになります。

Symantecの証明書警告

対象となる証明書は、Symantecの傘下ブランドのVeriSign・RappidSSL・Thawte・GeoTrustが含まれる点に注意してください。2017年に、Symantecは証明書事業をDigicertに譲渡しているので、この譲渡後に発行された証明書であれば問題ありません。とくに法人環境では社内向けのサイトが古い証明書を使っていないか確認しておく必要があります。

自社のサイトが該当しているか確認したい場合は、Symantec SSL Checkerというツールでチェックできます。

本件の背景を含めた詳細は、Mozilla Security Blogの記事を参照してください。

コンテンツブロック機能の対象が拡張されました

Firefoxにはトラッキングスクリプトをブロックする機能が含まれています。この機能が、ESR68で拡張され、暗号通貨マイニングなどを目的とするスクリプトもブロックできるようになりました。

これによって、設定可能な項目は4項目に増えました。以下に一覧表を示します。

種別説明デフォルト設定
トラッカー ユーザーの行動を追跡するスクリプト
例 - google-analystics.com
プライベートウィンドウのみブロック
トラッキングクッキー トラッカーによってセットされるCookie ブロックしない
暗号通貨マイニング ブラウザで暗号通貨をマイニングするスクリプト
例 - coinhive.com
ブロックしない
フィンガープリント採取ユーザーを一意識別する特殊な追跡スクリプト
例 - simility.com
ブロックしない

ブロック対象のリストはGitHubのレポジトリ mozilla-services/shaver-prod-lists で管理されています。Firefoxは定期的にMozillaのリスト配信サーバーと同期して、リストを取得します。リストの取得状況を確認したい場合は、アドレスバーに「about:url-classifier」と打ち込んでください。

注意が必要な点として、この機能を有効化した場合に、一部のサイトの動作への影響(主に埋め込み動画が再生されなくなる問題)が報告されている事に注意してください。

例) Bugzilla 1557363 コンテンツブロック有効時にibm.comの動画が再生できない

互換性を優先するか、安全性を優先するかに応じて、導入する設定を決める必要があります。

プライベートウィンドウでのアドオンの実行に許可が必要になります

アドオンがプライベートウィンドウでは原則として実行されなくなります。実行にはユーザーの明示的な許可が必要となり、ユーザーは画面から個別にアドオンを許可できるようになります。

プライベートウィンドウのアドオン実行

この変更は、企業運用でアドオンを一括導入している場合に問題になります。例えば、管理用のアドオンを導入している場合に、ユーザーがプライベートウィンドウを開いたときにアドオンが実行されなくなってしまうためです。

従来の挙動(プライベートウィンドウでも原則としてアドオンを実行する)に戻したい場合は、次の設定を適用して下さい。

pref("extensions.allowPrivateBrowsingByDefault", true)
RSSフィード機能が削除されました

FirefoxからRSSフィード機能(ライブブックマーク機能)が削除されました。従来はFirefoxにRSSフィードリーダーが標準搭載されていましたが、このリーダーがESR68からは使えなくなります。

RSSフィードリーダー機能

設定などで従来の挙動に戻すことはできないため、代替としてはウェブベースのリーダーを使うか、RSSフィードに対応したアドオンを導入する必要があります。

なお、ESR68に更新する際に、ライブブックマークのバックアップが自動的に作成されます。具体的には「Firefox feeds backup.opml」というOPML形式のファイルがデスクトップに作成されるので、他のリーダーに移行する場合は、このファイルをインポートしてください。

この削除の背景については、ブログ記事「Firefox removes core product support for RSS/Atom feeds」を参照してください。

Ctrl-Tabのタブ切替が「最終アクセス順」に変更になりました

ESR68ではCTRL-TAB押下時のタブ切り替えの挙動が大きく変わっています。CTRL-TABを押すと次のようなUIが表示されるようになりました(また、タブの切り替えの順番も変わっています)。

CTRL-TAB押下時の表示

この変更が適用されるのは、新規にFirefoxをインストールした端末のみです。ESR60がインストールされている環境でバージョン更新を行った場合には、新しいUIは有効化されません(この挙動は設定画面の『Ctrl+Tabで最近使用した順にタブを切り替える』の設定で管理されています)。運用する端末で使い勝手を統一したい場合は、次の設定を導入してください。

// falseで従来の挙動、trueで新しいUIを適用する
pref("browser.ctrlTab.recentlyUsedOrder", false);
ツールバーにFirefox Accountアイコンが追加されました

Firefox Account (Firefox Sync) とは、Mozillaのサーバーにブックマークや履歴を保存できる機能です。
ESR68では、ツールバーにFirefox Account用のアイコンが追加され、ここから機能にアクセスできるようになりました。

Firefox Accountアイコン

多くの企業では、情報セキュリティの観点からFirefox Account機能自体を無効化している場合が多いと思います。このアイコンを非表示にしたい場合には次の設定を導入します。

pref("identity.fxaccounts.toolbar.enabled", false);
インストールパスごとにユーザープロファイルが新規作成されます

Firefoxのインストールパスごとにプロファイルが新規作成されるようになります。たとえば、次のように2つのFirefoxをインストールしていたとします。

  1. /usr/lib/firefox
  2. /usr/local/lib/firefox

従来、この2つのFirefoxは起動時に同じユーザープロファイルを読み込んでいました。しかし、2つのFirefoxのバージョンが異なる場合に、(Firefoxのプロファイルは前方互換性がないので)バージョンの異なるFirefoxが交互にプロファイルを読み書きする結果、ブックマークの情報などが破損してしまう可能性がありました。

例)Support 1214384 Firefox 53にバージョンを戻すとブックマークが消失する

そこで、Firefox 68 ESRからは(1)と(2)のFirefoxは、起動時に別個のプロファイルを作成するようになりました。これによって、1つの端末に複数のFirefoxをインストールした場合にもプロファイルの破損が起こらなくなりました。

この仕組みの詳細については、Firefox 67以降のユーザープロファイルの仕様の詳細をご参照ください。

Windows 10の再起動時に自動起動するようになりました

Windows 10で、セッション終了時にFirefoxを開いていた場合、次の起動時にFirefoxが自動的に起動するようになっています。
一般的なアプリケーションの挙動と揃えた形になりますが、この機能を無効化したい場合は次の設定を導入します。

pref("toolkit.winRegisterApplicationRestart", false);
データ流出を起こしたサイトが検出されるようになりました

Firefoxに「データ流出を起こしたサイトを検知する機能」(Firefox Monitor機能)が導入されました。過去にデータ流出を引き起こしたサイトにアクセスした場合に、次のようなポップアップが表示されます。

Firefox Monitor機能

警告の表示対象となるサイトの一覧はFirefox Monitorの公式ページで確認できます。本記事の執筆時点で、約300サイトが対象サイトとして登録されています。

この機能を無効化したい場合は、次の設定を導入します。

pref("extensions.fxmonitor.enabled", false);
MSI形式インストーラの提供開始

従来はWindows向けにはexe形式のインストーラのみが提供されていましたが、MSI形式のインストーラが提供されるようになりました。Windows 7以降で利用することができます。

ダウンロード方法などの詳細についてはMozillaの公式ヘルプを参照ください。

自動更新の停止方法が変更になりました

企業環境では更新タイミングをコントロールするため、Firefoxの自動更新機能を無効化している場合が多いと思います。従来は、この無効化はAutoConfigを通じて実現することができましたが、ESR68からは「Policy Engine」という新しい仕組みの導入が必須になっています。

Policy Engineの詳細は、[Mozilla Firefox ESR60でのPolicy Engineによるポリシー設定の方法と設定項目のまとめ][20180512]を参照ください。自動更新の無効化が運用の前提になっている場合は、こちらの記事のガイドに沿ってPolicy Engineを導入してください。

まとめ

上述の通り、Firefox 68.0esrには、企業での運用に影響を与える変更が入っています。移行期限まで、あと2ヶ月を切りましたので、計画的に移行をお進め下さい。

タグ: Mozilla
2019-08-22

Firefoxのトラブルシューティング:Firefox 67以降のバージョンを起動すると意図せず別プロファイルが作られてしまう

2019年8月29日追記:この問題はFirefox 69以降およびFirefox ESR68.1.0以降では修正済みです。本稿はFirefox 67~68.0.x(ESR含む)に特有の現象についての解説となります。

Firefox 67以降のバージョンではFirefoxのインストール先ごとにプロファイルが作られるようになったという事をご紹介しました。しかし、起動の仕方によっては意図せず新しいプロファイルが作られてしまうという場面があります。

例えば、

  • デスクトップ上のショートカットからFirefoxを起動した時
  • コマンドプロンプト(cmd.exe)からパスを明示してFirefoxを起動した時
  • メールクライアントの本文内のURLをクリックして、URLを開く既定のアプリケーションとしてFirefoxを起動した時
  • テキストエディタから登録済みの外部アプリケーションとしてFirefoxを起動した時
  • Google Chrome用拡張機能を使ってリンク先をFirefoxで開いた時

のような場面で、同じ位置にインストールされているFirefoxなのに、それぞれ別々のプロファイルが作られてしまうという事が起こり得ます。これは何故でしょうか、そしてどうすれば回避できるでしょうか。

原因

この問題は、プロファイルを紐付ける対象のパスが正規化されず、大文字小文字が厳密に区別される事が原因で発生します。

通常、Windowsではファイルパスの大文字小文字は区別されません*1。また、ファイルには古いアプリケーション向けに、MS-DOS互換の短い名前が付いている場合があります。これらの理由から、一般的にWindows上では以下のパス表記はすべて等価に扱われます。

  • C:\Program Files\Mozilla Firefox(正式)
  • c:\Program Files\Mozilla Firefox(ドライブレターのみ小文字)
  • c:\program files\mozilla firefox(すべて小文字)
  • C:\PROGRAM FILES\MOZILLA FIREFOX(すべて大文字)
  • C:\PROGRA~1\MOZILL~1(MS-DOS互換の8.3形式)

ところが、Firefoxがインストール先パスとプロファイルとを紐付けるために使う情報は、当該フォルダのNTFSでのオブジェクトIDでもなければ正規化されたパス文字列でもなく、これらを単純な文字列として計算したCity Hash値です。City Hash値*2はパスの表記の仕方ごとに

  • C:\Program Files\Mozilla Firefox308046B0AF4A39CB
  • c:\Program Files\Mozilla Firefox4FD4C3CBEC5FE500
  • c:\program files\mozilla firefox4D589497A5E2C2E9
  • C:\PROGRAM FILES\MOZILLA FIREFOXB86E4C730D96F15B
  • C:\PROGRA~1\MOZILL~1A86124024953D658

と変化し、FirefoxはこのCity Hash値に対してプロファイルを作成し紐付けるため、「起動する時のパスの指定の仕方によってプロファイルが変わってしまう」という事が起こる訳です。

Firefoxを起動する手段が関連付けのみに依っているのであれば、この問題には遭遇しにくいです。問題が起こりやすいのは、ユーザーが明示的に文字列としてパスを指定する場合です。上記の例の「テキストエディタの登録済みの外部アプリケーション」や「Google Chrome用拡張機能で起動する外部アプリケーション」としてFirefoxを指定する場面では、正式な表記とは大文字小文字が異なるパスを自分で入力してしまいがちだからです。

対処

この問題はBug 1555319 - The case insensitive file system on Windows makes it possible to run Firefox with seemingly different installation pathsとして既にトラックされており、Firefox 69では修正済みとなっています*3。ただ、Firefox 68向けには修正がバックポートされていない*4ため、Firefox 67から68までのバージョンを使っている場合は手動での対策が必要です。

原因は上記の通りなので、対処としては、Firefoxを起動するためにパスを指定している箇所すべてについて、パス表記を正式な表記に揃えるという事になります。

正式なパス表記は、ファイルのプロパティを開いて「全般」タブの「場所」欄に表示される物です。firefox.exeをデスクトップなどにドラッグしてショートカットを作成し、そのプロパティを開いて「リンク先」欄の内容を参照しても同じパスを得られます。これらの方法で正式なパス表記を調べたら、Firefoxのパスを指定していた箇所を探して地道に設定し直していきましょう。

まとめ

Firefox 67以降のバージョンについて、起動の方法によって違うプロファイルが使われてしまう場合があるという問題の原因と回避策を解説しました。

当社ではFirefoxの法人での使用上で起こる様々な問題について、原因や回避方法の調査を有償にて承っています。社内でのFirefoxの運用でお困りのシステム運用担当者の方がいらっしゃいましたら、ぜひメールフォームよりお問い合わせ下さい。

*1 NTFSであればfsutilコマンドを使って特別な属性を与えることでファイル名の大文字小文字を区別するようにする事もできますが、伝統的なWindowsアプリケーションはファイルパスの大文字小文字が区別されない前提で設計されているため、一般的にはこの機能は使われていません。

*2 ファイル名部分を除外した、フォルダのパスのハッシュ値が使われます。

*3 Firefox側でパスを正規化してからCity Hash値を求めるようになりました。

*4 Firefox 69のブロッカーバグとして修正されたものの、Firefox 68に修正をバックポートするには遅すぎたとの事です。Firefox ESR68については、Firefox ESR68.1.0の時点で修正がバックポートされる見込みです。

タグ: Mozilla
2019-07-05

Firefox 67以降のユーザープロファイルの仕様の詳細

Firefox 67の新機能の1つに、インストール先ごとにプロファイルが分けられるようになったという物があります。

この記事では、Firefoxのユーザープロファイルの仕組みの歴史的な経緯や、プロファイル切り替えの仕組み自体がどのように使われてきたかという点を踏まえながら、Firefox 67での新機能の性質を解説します。

Firefoxの「ユーザープロファイル」

Firefoxのユーザープロファイルの仕組みは、元を辿ると、その前身となったNetscape Communicatorのユーザープロファイルの仕組みに行き着きます。

Netscape Communicatorが現役だった頃に広く使われていたWindows 95やWindows 98は、原則としてユーザーは1人だけであるという前提で設計されていたため、複数人で同じPCを共用する場合にユーザーを使い分けるという事ができませんでした。そのためNetscape Communicator独自の概念として「使用者ごとにユーザープロファイルを作り分けて、設定値やブックマークなどはその中で管理する」という仕組みが用意されました。

(図:Netscape Communicatorのユーザープロファイルをユーザーごとに使い分ける様子)

その一方で、Windows XP以降のバージョン*1ではOS自体が複数ユーザーを想定した設計になっています。アプリケーション側で個別にユーザープロファイルを管理する必要は無く、アプリケーションの設定を使用者ごとに使い分けたい場合、単純にWindowsのユーザーを使い分ければよいという事になっています。

(図:Windowsのプロファイルをユーザーごとに使い分ける様子)

以上のような歴史的な経緯があり、Firefoxのユーザープロファイルは「Windowsのユーザープロファイルごとに、複数のFirefoxのプロファイルが存在しうる」という少々複雑な状況となっています。

(図:Windowsのプロファイル上に複数のFirefoxのプロファイルが存在する様子)

実際には、Windowsのユーザーを使い分ければよい現状においては、使用者ごとにFirefoxのプロファイルを使い分けないといけないという状況はまず発生しません。よって、Firefoxのユーザープロファイルは今では1人のユーザーが、「仕事用」「開発用」「趣味用」といった何らかの用途ごとに使い分けるという用途が主流になっています。

(図:Windowsのプロファイル上で、用途ごとにFirefoxのプロファイルが使い分けられている様子)

「ユーザープロファイルの使い分け」から「コンテキストやコンテナーの使い分け」への変化

ただ、一般的なユーザーが普段使いにおいてFirefoxのユーザープロファイルを使い分けるということは、実際にはあまり無いものと思われます。その最大の理由は、運用の面倒さです。

Firefoxのユーザープロファイルを使い分けるには、

  • Firefoxの起動オプションに-pオプションを指定してプロファイルマネージャを起動し、そこでプロファイルを管理する。
  • about:profilesでプロファイルを管理する。

このいずれかの方法でプロファイルを作成し、さらに、

  • "C:\Program Files\Mozilla Firefox\firefox.exe" -p private(個人的な使用)
  • "C:\Program Files\Mozilla Firefox\firefox.exe" -p work(仕事での使用)
  • "C:\Program Files\Mozilla Firefox\firefox.exe" -p test(検証用)

のように起動オプションを変えたショートカットを複数用意する必要があります。

また、これだけでは「個人用のFirefox」「仕事用のFirefox」を並行して起動することができません。というのも、Firefoxのプロセスが既に起動している場合、別のプロセスで新たにFirefoxを起動しようとすると、既に起動している方のプロセスの方にプロセスが吸収されてしまう(そちらでウィンドウやタブが開かれる)という結果になるからです。これを回避するためには、

  • "C:\Program Files\Mozilla Firefox\firefox.exe" -p private
  • "C:\Program Files\Mozilla Firefox\firefox.exe" -p work -no-remote
  • "C:\Program Files\Mozilla Firefox\firefox.exe" -p test -no-remote

のように、普段使いの(URLなどの関連付けからFirefoxが起動された時に使う)プロファイルを除いて他のショートカットには-no-remoteオプションを指定し、前述の「既存プロセスに吸収される」挙動を無効化する必要があります。

また別の方法として、プロファイルマネージャを使用せずに以下のようにする方法もあります。

  • "C:\Program Files\Mozilla Firefox\firefox.exe" -profile "C:\Users\username\private-profile" -no-remote

-profileオプションで任意のフォルダをフルパスで指定すると、プロファイルマネージャの管理下にないフォルダであっても、それをプロファイルとしてFirefoxを起動できます。実験や検証のためのプロファイルをいくつも併用したり使い捨てにしたりという使い方をしたい場合、プロファイルマネージャを使わずともフォルダを用意するだけで済むため、この方法は非常に便利です。ただしこの場合も、-no-remoteを付けないと「既に起動している方のプロセスの方にプロセスが吸収される」という動作になってしまう点には注意が必要です。

これだけ面倒な手順が必要なわりに、一般的なユーザーが普段使いで得られるユーザー体験はあまり良い物ではありません。というのも、実際の利用局面では「仕事中に見つけた面白そうな記事を個人用にブックマークしておく」「個人的な使用中に見つけた仕事に関係する記事を、仕事中に履歴から探す」といった場面が生じやすいのに対し、履歴やブックマークなどがプロファイルごとに別々に保存されていると、そういった「用途をまたいだ情報の共有」ができないからです。

この問題の解決策として現在のFirefoxには、「1つのユーザープロファイルで、閲覧履歴やブックマークなどは共有しつつ、起動中の1つのプロセスの中でログイン状態やCookieなどの認証情報は分離する」という事を可能にする、以下の機能が備わっています。

  • プライベートウィンドウ(そのウィンドウの中で閲覧したページには、通常モードで閲覧した時のCookieなどが通知されない)
  • コンテナータブ(用途ごとに認証情報を切り替える)

これらの機能は、「諸々の不便を被ってでも厳密にプロファイルを分けたい程ではない」「しかし、ログイン状態やCookieなどの認証情報は用途ごとに切り替えたい」という、実際の使用局面でよく見られるニーズに応えるものとなっています。

(図:コンテナーを使い分けている様子)

ユーザープロファイルの使い分けよりもはるかに手軽に使えるため、これらの機能で充分に用を果たせる場面では、ユーザープロファイルの使い分けのニーズはほぼ無くなったと言ってよいでしょう。

それでも残った「ユーザープロファイルを使い分ける必要がある場面」

以上のような経緯から、現在のFirefoxで「ユーザープロファイルを使い分けなければその目的を達成できない」場面は非常に限られています。その代表的な例が、複数バージョンのFirefoxの並行起動です。

(図:複数バージョンのFirefoxを専用プロファイルで使い分けている様子)

例えば、前述の手順を用いて複数バージョンのFirefoxを並行起動する場合、以下のように起動オプションでプロファイルを指定する事になります。

  • "C:\Program Files\Mozilla Firefox\firefox.exe" -p default(64bit版Firefox)
  • "C:\Program Files (x86)\Mozilla Firefox\firefox.exe" -p 32bit -no-remote(32bit版Firefox)
  • "C:\Program Files\Mozilla Firefox Beta\firefox.exe" -p beta -no-remote(ベータ版)

Firefox 67からの変更は、まさにこの用途のためのものです。言い換えると、Firefox 67以降のバージョンでは、「インストール先が異なるFirefoxの実行ファイルごとに、専用のユーザープロファイルを使用する」使い方が、特にユーザー側での工夫無しに自動的に行われるようになっているという事になります。

Firefoxが自身のインストール先を識別する処理の流れ

では、このような挙動は一体どのようにして実現されているのでしょうか。特に、「特定のインストール先のFirefox」と「特定のユーザープロファイル」とはどのように紐付けられているのでしょうか。鍵になるのは、インストール先のパスに基づくCity Hash値です。

Firefox 67以降のバージョンでは、Firefoxはプロセスの起動時に、自身の実行ファイルが置かれたフォルダの位置からCity Hashのアルゴリズムに基づいてハッシュ値を求めます。例えばFirefoxがC:\Program Files\Mozilla Firefoxにインストールされていた場合、値は308046B0AF4A39CBのようになります。内部的にはこれは「install hash」と名付けられている模様です。

次にFirefoxは、ユーザープロファイルが置かれている%AppData%\Mozilla\Firefox(具体的には C:\Users\ユーザー名\Appdata\Roaming\Mozilla\Firefox)の位置にあるprofiles.iniから[Install(install hash)]という名前のセクションを探します。これは通常、以下のような内容になっています*2

; こちらは従来からあるセクション
[Profile0]
Name=default
IsRelative=1
Path=Profiles/xxxxx.default

; 自動的に追加されたセクション
[Install308046B0AF4A39CB]
Default=Profiles/xxxxx.default
Locked=1

このDefaultの値がprofiles.iniから見た相対パスとなっており、このパスを解決することで、特定のインストール先のFirefoxに対して紐付けられたプロファイルフォルダを特定できるというわけです。この仕組みがあるお陰で、関連付け等からFirefoxが起動された場合などで起動オプションでプロファイルが明示されていなくても、適切なプロファイルが自動的に選択されるようになっています。

ただし、同じインストール先であっても、起動時のパスの指定の仕方によってはプロファイルが意図せず切り替わってしまう場合があります(別記事にて詳細な解説)。Firefoxのパスを明示的に指定する場面では、必ず正式なパス表記を使うように注意して下さい。

なお、この機能について「Firefoxのバージョンごとにプロファイルが別れる」というような説明がなされている場合がありますが、以上の仕組みを見て分かる通り、プロファイルはあくまでFirefoxのインストール先のパスに紐付いています。インストール済みのFirefoxに別のバージョンのFirefoxを上書きインストールしたり、Firefox自身の自動更新機能で新しいバージョンに更新したりした場合であっても、Firefoxのインストール先が変わらなければ、プロファイルは以前の物が引き続き使われます。「Firefoxを更新したらその度に新しいプロファイルが作られる」という事はありません。(逆に言うと、この機能を使ってプロファイルを使い分けるためには、必ずそれぞれのバージョンのFirefoxを別々の位置にインストールする必要があります。)

Windowsのレジストリ上での取り扱い

上記のinstall hashはWindowsのレジストリ上でも使われています。

従来は、Windowsのレジストリ上はFirefoxはあくまで「Firefox」という名前の1つのアプリケーションとして扱われており、複数のバージョンを異なるフォルダにインストールした場合は最後にインストールした物(最後にインストーラがレジストリに書き込みを行ったバージョン)がその代表として扱われるようになっていました。例えばシステム標準のブラウザの選択肢の項目は

  • HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\Firefox
  • HKEY_CURRENT_USER\Software\Clients\StartMenuInternet\Firefox

とその配下に記録された情報に基づいて表示されていました。

Firefox 67以降のバージョンでは、この情報がインストール先ごとに書き込まれるようになっています。

  • HKEY_LOCAL_MACHINE\SOFTWARE\Clients\StartMenuInternet\Firefox-(install hash)
  • HKEY_CURRENT_USER\Software\Clients\StartMenuInternet\Firefox-(install hash)

同様に、関連付け対象のファイルやデータの型も

  • HKEY_CLASSES_ROOT\FirefoxHTML-(install hash)
  • HKEY_CLASSES_ROOT\FirefoxURL-(install hash)

のようにそれぞれインストール先ごとに登録されるようになりました。このように、Windowsのレジストリ上はインストール先ごとのFirefoxはそれぞれ別々のアプリケーションとして認識されています

アプリケーションの一覧上でそれぞれのインストール先を識別できない問題の回避策

以上の通り、Windowsのシステム上は各インストール先のFirefoxは別々の物として認識されているわけですが、ここで1つ問題があります。内部的にはそれぞれ別々のinstall hashを伴って認識されているものの、表示されるアプリケーション名としてはどれも「Firefox」となるため、標準のブラウザや関連付けの対象を選択する場面で同じ名前の項目がいくつも並んでしまうという事が起こってしまうのです。

(複数のバージョンのFirefoxが同じ名前で並んでいる様子)

現在の所、この問題を解決するには手動でのレジストリの編集が必要です。この一覧に表示されるアプリケーション名は HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\Shell\MuiCache というキーの値が参照されており、

  • C:\Program Files\Mozilla Firefox\firefox.exe.FriendlyAppName のデータ→Firefox Release
  • C:\Program Files\Mozilla Firefox ESR\firefox.exe.FriendlyAppName のデータ→Firefox ESR

のように実行ファイルのパス.FriendlyAppNameという名前の値のデータをそれぞれ編集しておくと、インストール先ごとの項目が分かりやすい名前で表示されるようになります。

(複数のバージョンのFirefoxにそれぞれ別の名前が付いている様子)

起動オプションの作用はどう変わったか

上記の通り、Firefox 67以降のバージョンは自分自身のインストール先に基づいて適切なプロファイルを自動的に選択するようになったわけですが、では、今まで使われていた「起動オプションでプロファイルを明示する」機能はどのような影響を受けたのでしょうか。

-p プロファイル名

前述した通り、Firefox 67以降のバージョンでは%AppData%\Mozilla\Firefox\profiles.iniに以下のように[Install(install hash)]という名前のセクションが追加されます。

; 従来からあるセクション
[Profile0]
Name=default
IsRelative=1
Path=Profiles/xxxxx.default

; 自動的に追加されたセクション
[Install308046B0AF4A39CB]
Default=Profiles/xxxxx.default
Locked=1

この時、2つのセクションで同じパスが参照されている点に注目して下さい。Firefoxは参照先のパスが一致する2つのセクションを関連付けて認識しています。そのため、以下の2つのコマンド列は同等として扱われます

  • "C:\Program Files\Mozilla Firefox\firefox.exe" (install hashに基づいて自動的にプロファイルを選択)
  • "C:\Program Files\Mozilla Firefox\firefox.exe" -p default-pオプションでプロファイルを明示)

引数無しで起動したFirefoxのプロセスがある状態でプロファイルを明示してFirefoxを起動しても、逆に、プロファイルを明示して起動したプロセスがある状態で引数無しでFirefoxを起動しても、既に起動している方のプロセスに処理が吸収される(既存プロセスの方でウィンドウまたはタブが開かれる)という、従来の-no-remoteオプション無しの動作と似た結果になります。

同じバージョン・同じインストール先のFirefoxを、別プロセス・別プロファイルで起動する

別のプロファイルを指定して別のプロセスを並行動作させたい場合、従来は-p 別のプロファイル名と指定するだけでは不十分で、-p 別のプロファイル名 -no-remoteと指定する必要がありました。Firefox 67以降のバージョンではこの点が改善され、-p 別のプロファイル名と指定するだけで別プロセスのFirefoxを並行動作させられるようになりました

従来は-no-remoteオプションが必須だったため、必然的に、これらのオプションを指定したショートカットからFirefoxを多重起動しようとすると、「既存プロセスに処理が吸収されない」「しかし、新しいプロセスで使おうとしているプロファイルは、別のプロセスによって既に使用中」ということで、「Firefoxは起動していますが応答しません。新しいウィンドウを開くには既存のFirefoxをプロセスを終了させなければなりません。」というメッセージが表示されてしまうという結果になっていました。Firefox 67以降では、この制限に煩わされる事はもうありません。

-profile プロファイルのフルパス

プロファイルをフルパスで指定して起動する場合も同様に、-no-remoteオプション無しでの別プロセス起動が可能となりました。以下のように起動オプションを指定すると、それぞれのプロファイルでFirefoxのプロセスが並行して動作する状態になります。

  • "C:\Program Files\Mozilla Firefox\firefox.exe" -profile "C:\Users\username\profile1"
  • "C:\Program Files\Mozilla Firefox\firefox.exe" -profile "C:\Users\username\profile2"

この場合、同じ起動オプションでFirefoxを多重起動すると、既に起動していてそのプロファイルを使用しているプロセスに処理が吸収されます。

また、条件を整えると、「起動オプションでプロファイル名を明示する場合」と「フルパスで明示する場合」を等価に扱うことや、あるいは、「プロファイル名を明示」「フルパスで明示」「プロファイルを明示しない」の3つを等価に扱うという事も可能になっています。

重要なのは以下の点です。

  • 当該プロファイルがプロファイルマネージャの管理下に入っている(profiles.iniにそのフォルダの情報が記載されている)。
  • 当該プロファイルのプロファイルマネージャ上の名前と、フォルダ名とが一致している。

以下は、profiles.iniを編集して上記の条件を満たすように設定したプロファイルの例です。

[Profile0]
;Name=default
Name=xxxxx.default
IsRelative=1
Path=Profiles/xxxxx.default

Firefoxのプロファイルマネージャはプロファイルを作成する際、表示用の名前の前にランダムな文字列を付与してフォルダを作成します*3この表示名が記載されているName=の行を編集し、表示名がプロファイルのフォルダ名と一致する状態にします。この状態であれば、以下の2つのコマンド列は等価に扱われるようになります。

  • "C:\Program Files\Mozilla Firefox\firefox.exe" -profile "%AppData%\Mozilla\Firefox\Profiles\xxxxx.default"
  • "C:\Program Files\Mozilla Firefox\firefox.exe" -p xxxxx.default

また、install hashとの紐付けが

[Profile0]
Name=xxxxx.default
IsRelative=1
Path=Profiles/xxxxx.default

[Install308046B0AF4A39CB]
Default=Profiles/xxxxx.default
Locked=1

のように行われていれば、以下の3パターンがすべて等価に扱われるようになります。

  • "C:\Program Files\Mozilla Firefox\firefox.exe" -profile "%AppData%\Mozilla\Firefox\Profiles\xxxxx.default"
  • "C:\Program Files\Mozilla Firefox\firefox.exe" -p xxxxx.default
  • "C:\Program Files\Mozilla Firefox\firefox.exe"

ただ、前述した通り、Firefox 67以降での新機能の恩恵を受けるためには、プロファイルをプロファイルマネージャの管理下に置く必要がある、という点に注意が必要です。「フルパスでプロファイルを明示したい場面」と「プロファイル指定無しでプロファイルを自動認識させたい場面」が重なる事はあまりありませんが、この両方のニーズを同時に満たしたいという場合*4には、見落としが生じないようにくれぐれも気をつけて下さい。

まとめ

以上、Firefox 67以降での「Firefoxのインストール先ごとのユーザープロファイルを使用する挙動」の詳細について解説しました。

Google Chromeが覇権を取った現在においては、Firefoxのニーズは一般ユーザーよりも(おそらくは検証用として)Web制作・Webアプリ開発を業としている人の方に偏っている模様です。「複数バージョンを並行して起動して検証する」という場面で特に有用なこの機能が導入されたのも、そのような背景があったからという事ではないかと考えられます。筆者ほど多くのバージョンを使い分ける事はそうそう無いと思われますが、通常リリース版・ベータ版・ESR版の3つを並行起動できるだけでも検証の負担は下がります。皆さんもこれを機に試してみてはいかがでしょうか。

また、今回の調査は現在Firefox ESR60を運用中のお客様にFirefox ESR68をご案内するにあたって、変更点の詳細を把握するために行いました。当社の法人向けFirefoxサポートでは、詳細な技術情報が提供されていない新機能の詳細の調査も有償にて承っております。「SIの業務において、お客さまの承認を得るために詳細なエビデンスの提出が求められているが、どこを対象に調査すればよいのか分からない」といった問題でお困りの方は、メールフォームよりぜひお問い合わせ下さい。

*1 正確には、Windows 2000やそれ以前のWindows NTなども含みます。

*2 Firefox 67以降のバージョンを初めて起動した時に、このような情報が追記されます。

*3 これは、ユーザープロファイルの位置を決め打ちで特定しにくいようにして、悪意の攻撃者の被害を受けにくくするための工夫です。

*4 例えば、web-ext経由でFirefoxを起動して常用しているというような場合。

タグ: Mozilla
2019-06-14

Thunderbirdアドオン「CardBook(連絡先)」でローカルに保存されるデータの暗号化に対応しました

CardBookと企業利用

皆さんはCardDAVという仕様をご存じでしょうか? CardDAVはWebDAVのプロトコルを使ってLDIF形式のアドレス帳をやり取りするという物で、これを用いると「読み書き両方を行えて、内容が複数PC間で同期される」という種類のリモートアドレス帳を汎用の物として実現することができます。CardDAVサーバーとして振る舞える製品にはownCloudやDAViCalなどがあり、読み取り専用に設定したリモートアドレス帳を複数人で共有するという事もできますので、企業利用では重宝する場面がありそうです。

このように便利なCardDAVですが、残念ながらThunderbirdは本体の機能としては対応していません。CardDAVベースのリモートアドレス帳を使うにはアドオンをインストールする必要があります。CardBookは、そのようなCardDAV対応のためのアドオンの一例です。

ところで、企業によっては個人情報の取り扱い方について、「顧客や取引先の個人情報をローカルに保存する際は必ず暗号化する」といったプライバシーポリシーを定めている場合があります。前出のCardBookはリモートアドレス帳のデータをIndexedDBを使用してローカルにキャッシュする設計で、この時のデータは暗号化されないため、そのままでは前述のポリシーに抵触するので採用できないという事になります。

そのような背景から、「CardBookでローカルに保存されるデータを暗号化したい」というご相談を頂き、成果を開発元に還元する前提で先行して作業を進めていたのですが、残念ながら受注には至らず、手元には実現可能性の調査のために行った試験的な実装が残るという結果になりました。しかしせっかく実装した物をそのまま放置しておくのも勿体なかったので、CardBookプロジェクトに還元したところ、標準機能の1つとして取り込まれるに至りました。現在リリース済みのCardBook 33.9以降のバージョンでは、設定画面でチェックボックスをONにすればローカルデータの暗号化が有効になるようになっています。

以下、CardBookのローカルデータベースの暗号化を実現するにあたって行った具体的な内容をご紹介します。

IndexedDBに格納するデータの暗号化と復号

幸い、Thunderbirdの基盤であるGeckoには、暗号化のための汎用APIであるWeb Crypto APIが実装されています。あるのなら使わない理由はありませんので、CardBookでもデータの暗号化はWeb Crypto APIによる共通鍵暗号で行う事にしました。何故公開鍵暗号ではなく共通鍵暗号なのかについては別項で詳しく述べていますので、そちらも併せてご覧下さい。

実装は、まず暗号化・復号を行う専用のモジュールを追加した上で、IndexedDBの読み書きを行うモジュールの書き込み用のデータを用意する箇所に暗号化処理を読み込んだデータを検証する箇所に復号処理を仕掛けることで、他のモジュールに影響を与えず透過的に動作するような組み込み方としました。

この時気をつけなくてはならないポイントとして、暗号化をどのタイミングで行うかという点が挙げられます。以下、暗号化を行っている実際の箇所を抜粋しながら説明します。

元々の設計では、IndexedDBへのデータ書き込みは以下の要領で行われていました。

addCard: unction (aDirPrefName, aCard, aMode) {
  var db = cardbookRepository.cardbookDatabase.db;
  // トランザクション開始
  var transaction = db.transaction(["cards"], "readwrite");
  var store = transaction.objectStore("cards");
  var storedCard = aCard;
  // データの書き込み
  var cursorRequest = store.put(storedCard);

  // 以下、成功時・エラー時の処理
}

ここに暗号化処理を組み込むのですが、Web Crypto APIは暗号化したデータがPromiseで返されるため、値を使うには.then()のコールバック関数で受け取るか、awaitで値の解決を待つ必要があります。コールバック関数を使うスタイルで実装するにはこのメソッドの書き方を大幅に変えなくてはなりませんが、asyncキーワードとawaitを使うと、この同期処理の関数を容易に非同期処理に対応させることができます。

addCard: async function (aDirPrefName, aCard, aMode) { // asyncキーワードを追加
  var db = cardbookRepository.cardbookDatabase.db;
  // トランザクション開始
  var transaction = db.transaction(["cards"], "readwrite");
  var store = transaction.objectStore("cards");
  // 暗号化処理を追加
  var storedCard = cardbookIndexedDB.encryptionEnabled ? (await cardbookEncryptor.encryptCard(aCard)) : aCard;
  // データの書き込み
  var cursorRequest = store.put(storedCard);

  // 以下、成功時・エラー時の処理
}

当初はこの例のように、書き込みを行う直前で暗号化を行うようにしていました。しかし実際に動作させてみると、これではIndexedDBでのデータ書き込みに失敗するという結果になりました。何故でしょうか?

実は、IndexedDBでのデータ書き込みはトランザクション開始から書き込みまでを同期的に(同じイベントループ内で)行う必要があります。この例ではトランザクション開始後にawaitを使ってしまっているせいで、store.put(storedCard)が次のイベントループでの実行となってしまい、そのせいで書き込みに失敗してしまうという訳です。

そのため最終的な実装では、以下の例のようにトランザクション開始前に暗号化を終えておくようにしました。

addCard: async function (aDirPrefName, aCard, aMode) {
  // 暗号化
  var storedCard = cardbookIndexedDB.encryptionEnabled ? (await cardbookEncryptor.encryptCard(aCard)) : aCard;
  var db = cardbookRepository.cardbookDatabase.db;
  // トランザクション開始
  var transaction = db.transaction(["cards"], "readwrite");
  var store = transaction.objectStore("cards");
  // データの書き込み
  var cursorRequest = store.put(storedCard);

  // 以下、成功時・エラー時の処理
}

これなら、トランザクション開始から書き込みまでが同期的に行われるため問題ありません。

復号時には、特にこのような注意は必要ありません。また、元々IndexedDBからのデータ読み取りは結果が非同期で返されるので、CardBookのデータ読み込み処理もその前提で設計されていました。そのため、IndexedDBから返ってきたデータを非同期で復号した上で返却するという処理を挟み込んでも、CardBookのデータ読み込み処理全体としてはインターフェースを変えずに済んだのでした。

パスワード入力を求める方式にしなかった理由

CardBookのローカルデータ暗号化では、暗号化・復号に使う共通鍵は、バックグラウンドで自動生成した物を暗黙的に使い、鍵自体をユーザープロファイル内に保存する形としました。

「暗号化されたデータと鍵を同じ場所に置いておくのでは、暗号化の意味が無いじゃないか」と思うでしょうか? 実際、変更をフィードバックした際にもCardBookプロジェクトの開発者の方からも「パスワード入力を求める方式にした方がいいのではないか?」という質問がありました。Web Crypto APIの機能を使うとユーザーが入力したパスワードから秘密鍵を作る事もできる(Web Crypto APIの解説記事の「パスワードを鍵に変換する」の項をご参照下さい)のに、そうしなかったのは何故でしょうか。

ここで一旦、パスワードの安全な運用という事を考えてみましょう。パスワードを自分で記憶しておきその都度入力するという方式は、一見すると安全なように思えます。しかしながら、運用の仕方によっては却って危険になる場合があります。

  • パスワード入力には、肩越しに入力の様子を覗き見るショルダーハックや、キーの入力を監視するキーロガーなどによってパスワードを盗み取られるリスクがあります。パスワード入力の頻度が多ければ多いほど、このリスクは高まります。
  • 人間の記憶容量には限りがあるため、あまり複雑なパスワードを複数覚えるという事はできません。そのために「同じパスワードを何度も使い回す」「推測が容易なパスワードにする」といった事が行われてしまい、そうなると却って危険な状態となります。
  • 定期的なパスワード変更にも、同様の問題があります

これらの理由から、パスワードの入力は「複雑で憶えにくいパスワードを1つだけ覚える」「それをマスターパスワードとして使い、それ以外はパスワードマネージャに憶えさせる」という運用にするのが比較的安全だというのが現在の定説となっています*1

「企業でThunderbirdを使う」というシチュエーションでは、「PCのログオン」「受信メールサーバーの認証」「送信メールサーバーの認証」などでそれぞれパスワードの入力が発生する可能性があります。という事は、ここにさらに「ローカルデータの復号」のためのパスワードが加わるというのは、さすがに実運用を妨げるレベルの煩わしさでしょう。かといって、他の部分ではパスワードを使用していないのにここでだけパスワードの入力を求める、というアンバランスな運用も考えにくいです。そういった事を考慮した結果として、CardBookのローカルデータ暗号化は現在比較的安全とされている運用を想定し、

  • 秘密鍵は、自動生成した物をJWK形式でエクスポートし、「長いパスワード文字列」の一種としてThunderbirdのパスワードマネージャに記憶させる。
  • 秘密鍵の保護が必要な場合は、使用者が任意でThunderbird本体のマスターパスワード機能を有効化する。

というポリシーを採用する事にしたのでした。

まとめ

Thunderbird用アドオンのCardBookに対して行った、ローカルデータの暗号化対応の概要をご紹介しました。

当社では、一般に公開されているFirefox用アドオン・Thunderbird用アドオンをはじめとした様々なフリーソフトウェア・OSSについて機能追加・改造のご依頼を承っております。また、成果をアップストリームに還元しても差し支えがないケースでは、積極的に還元を行うようにしています。自社でフリーソフトウェア・OSSを採用したいが少しだけ要件に合わない、という事でお悩みの場合には、メールフォームからお問い合わせ下さい。

*1 ただし、これはあくまで現時点での話です。技術の進歩や、この分野での研究が進む事などによって、「最もマシ」なやり方は変わっていく可能性があります。

2019-05-28

タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|