2020年に発表され、2021年のGoogle Chrome 88以降のバージョンで既に利用可能となっている、Chrome用拡張機能の仕様の大規模アップデートである「Manifest V3」では、それまであったwebRequest
と呼ばれるAPIが廃止されています。
ですが、いつまで可能かという期間は明記されていないものの、主に法人運用向けとして、特定の条件を満たすことでこのAPIの利用を継続できるようになっています。
この記事では、webRequest
によるブロッキングをManifest V3でも行う具体的な方法について解説します。
背景
webRequst
は、ブラウザー上で発生したHTTP(HTTPS)の全リクエストを、あらかじめ登録しておいたリスナーで監視し、読み込みの中止・別のURLへのリダイレクト・まったく別のコンテンツの返却といった任意の操作をスクリプタブルに行える、非常に強力なAPIです。
その機能ゆえに古くから広告ブロッカーの実装に使われてきましたが、すべてのHTTP(HTTPS)リクエストに対してJavaScriptの関数を実行する性質上、場合によってはWebブラウジング全体の性能低下を招く恐れがあります。
GoogleのChrome開発チームはユーザーの体感パフォーマンスを強く優先する方針であることは、昔からよく知られています。
そのため、そのようなパフォーマンスの悪影響を最小化することを目的として、Manifest V3ではwebRequest
を廃止し、代わりに静的なマッチングパターンのリストのみを受け付けるdeclarativeNetRequest
という宣言的APIへ置き換えることが告知されていました。
他方で、柔軟なブロッキングが行えなくなるため、ユーザーや拡張機能の開発者からは「広告収入に依存しているGoogle社が、広告ブロッカーでは自社の広告をブロックできないようにする事が最大の目的なのではないか」「広告ブロックの実用性が大幅に低下するのではないか」といった懸念が示されてきました1。
ところで、企業での運用では(少なくとも当社のお客さまでは)広告ブロックの出番は無い模様ですが、それ以外の用途でこのAPIは重宝されてきました。 具体的には、業務中にアクセスさせたくないWebサイトについてコンテンツフィルタ的にアクセスを遮断するものや、それ以外にも、監査用のログ収集や、読み込んだWebページに応じたブラウザーの自動切り替えなどの用途があります。
当社でも、「ページ遷移の要求を検知して、URLに基づいて適切なブラウザーを判定し、現在のブラウザー以外で閲覧する対象であった場合には、読み込みを中断して別のブラウザーにURLを引き渡す」という方法でWebブラウザーの自動切り替えを行う、以下のような拡張機能を複数種開発しています。
- IE View WE(主に個人用途向け)
- BrowserSelector(法人利用向け・3つ以上のブラウザーに対応)
Manifest V3への移行とManifest V2の廃止以後もこれらの拡張機能を使える状態にするためには、何らかの対応を取らなくてはなりません。
Manifest V3でのwebRequst APIの継続使用は可能か?
当初はManifest V3の正規の方法(静的なマッチングリスト)の機能を使ってこれらの拡張機能の機能を維持できないかと考えていましたが、調査の結果、それは不可能であることが分かりました2。
そこで注目したのが、従来通りのwebRequest
APIを使い続ける方法です。
既存の拡張機能のManifest V3への移行方法を解説する記事の「Can Manifest V3 extensions use blocking Web Request?」の項には、以下のような記載があります。
The blocking version of the Web Request API exists in Manifest V3, but it can only be used by extensions that are force-installed using Chrome's enterprise policies: ExtensionSettings, ExtensionInstallForcelist.
訳:
読み込みの中断を行える版のWeb Request APIはManifest V3にも存在していますが、Chromeのエンタープライズポリシー(ExtensionSettingsやExtensionInstallForcelist)で強制インストールされた拡張機能からのみ使えます。.
これは、具体的には以下の事を指します。
- https://support.google.com/chrome/a/answer/187202?hl=ja#zippy=%2Cwindows から
Google Chromeバンドル
をダウンロードし、保存されたzipファイルを展開する。 Configuration\admx\*.admx
と、Configuration\admx\en-US
やConfiguration\admx\ja
などを、ドメインコントローラのC:\Windows\Sysvol\domain\Policies\PolicyDefinitions
にコピーする(ドメイングループポリシーとして使用)。 または、操作中のWindows PCのC:\Windows\PolicyDefinitions
にコピーする(ローカルグループポリシーとして使用)。- グループポリシーの管理画面(
gpedit.msc
)を起動し、ドメインのポリシーまたはローカルコンピューターのポリシーで、コンピューター又はユーザーを対象として、管理用テンプレート
→Google
→Google Chrome
→拡張機能
→自動インストールするアプリと拡張機能のリストの設定
)を開く。 - 設定値を
有効
に切り替える。 表示...
をクリックする。- 設定のデータ一覧に、対象のChrome拡張機能のIDを追加する。
Edgeの場合も、ポリシーテンプレートのダウンロード元が異なる以外は、基本的に手順は同じです。
ただ、実際にやってみたところ、拡張機能の開発者の観点からはいくつかのハマリ所がありました。
「パッケージ化されていない拡張機能を読み込む」の代わりに行う、ローカルでのインストール方法
拡張機能の開発者が作業をする際は、開発中のバージョンを「パッケージ化されていない拡張機能を読み込む」機能で一時的にインストールして動かす場合が多いでしょう。
ですが、Manifest V3でwebRequest
APIを使う拡張機能では、この方法での開発は不可能です。
というのも、先の引用箇所の「Chromeのエンタープライズポリシーで強制インストールされた拡張機能からのみ使えます」という制限が愚直に適用されるために、この方法で読み込んだ拡張機能からはwebRequest
APIを利用できないからです3。
言い換えると、例え開発段階であっても、Manifest V3でwebRequest
APIを使うためには、その拡張機能を前項で述べた手順を用いてグループポリシーでインストールしなくてはなりません。
とはいえ、機密保持の観点からも、現実的な作業効率の観点からも、開発段階で何か変更をする度に拡張機能をChromeウェブストアにアップロードするというのは無理があります。
このような場面では、独自ストアで拡張機能を公開する場合と同様の手順を踏んで、ローカルにある仮想的なストアから拡張機能が提供されているものと見なしてインストールさせる方法が有効です。 具体的な手順は以下の通りです。
- 拡張機能の開発版パッケージを用意する。
- Chromeを起動する。
- 拡張機能の管理画面(
chrome:extensions
)を開く。 デベロッパーモード
を有効化する。拡張機能をパッケージ化
で、拡張機能のmanifest.json
が置かれているフォルダーを選択して、パックする。 説明を簡単にするため、ここでは仮にmanifest.json
がC:\Users\Public\myextension\manifest.json
の位置にあるとする。 これにより、1つ上のディレクトリーにmyextension.crx
とmyextension.pem
が作られる。myextension.crx
をChromeの拡張機能の管理画面にドラッグ&ドロップし、インストールして、IDを控える。 ここでは、得られたIDがegoppdngdcoikeknmbgiakconmchahhf
であったと仮定する。- 拡張機能を一旦アンインストールする。
C:\Program Files (x86)\ClearCode\BrowserSelector\BrowserSelectorTalkChrome.json
の"allowed_origins"
に、先ほど控えたIDに基づくURLを追加する。 先のIDが得られた場合であれば、追加するURLは"chrome-extension://egoppdngdcoikeknmbgiakconmchahhf/"
となる。
- インストール用マニフェストファイルを作成する。
先ほど控えたIDを含める形で、以下のような内容のXMLファイルを作成し、
myextension.crx
と同じ位置に置く。 ここではC:\Users\Public\manifest.xml
の位置に置いたと仮定する。このとき、<?xml version='1.0' encoding='UTF-8'?> <gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'> <app appid='egoppdngdcoikeknmbgiakconmchahhf'><!-- 先ほど控えたIDを書く --> <updatecheck codebase='file:///C:/Users/Public/myextension.crx' version='1.0.0' /><!-- `myextension.crx` の実際のFile URLを書く --> </app> </gupdate>
version
の値はmanifest.json
に記述された実際のバージョンに合わせる。 - Chromeのグループポリシーテンプレートを使い、Chromeで拡張機能を読み込むための設定を行う。
- ポリシー管理画面で、Chromeのグループポリシーの設定項目の中の
自動インストールするアプリと拡張機能のリストの設定
を開く。 - 設定のデータ一覧に
<Chrome拡張機能のID>;<マニフェストファイルの位置>
を追加する。 ここまでの例に倣った場合、egoppdngdcoikeknmbgiakconmchahhf;file:///C:/Users/Public/manifest.xml
のようになる。
- ポリシー管理画面で、Chromeのグループポリシーの設定項目の中の
- Windows端末がドメイン参加状態でない場合、管理者権限で
cmd.exe
を開き、以下のコマンド群を実行してドメイン参加状態にする。 (参考: https://hitco.at/blog/apply-edge-policies-for-non-domain-joined-devices/ )reg add HKLM\SOFTWARE\Microsoft\Enrollments\FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF /v EnrollmentState /t reg_dword /d 1 /f reg add HKLM\SOFTWARE\Microsoft\Enrollments\FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF /v EnrollmentType /t reg_dword /d 0 /f reg add HKLM\SOFTWARE\Microsoft\Enrollments\FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF /v IsFederated /t reg_dword /d 0 /f reg add HKLM\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts\FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF /v Flags /t reg_dword /d 0xd6fb7f /f reg add HKLM\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts\FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF /v AcctUId /t reg_sz /d "0x000000000000000000000000000000000000000000000000000000000000000000000000" /f reg add HKLM\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts\FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF /v RoamingCount /t reg_dword /d 0 /f reg add HKLM\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts\FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF /v SslClientCertReference /t reg_sz /d "MY;User;0000000000000000000000000000000000000000" /f reg add HKLM\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts\FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF /v ProtoVer /t reg_sz /d "1.2" /f
- Chromeを起動し、拡張機能が自動的にインストールされることを確認して、動作を検証する。
- Windows端末がドメイン参加状態でなかった場合、検証が終了したら、以下の手順でドメイン非参加状態に戻す。
管理者権限でコマンドプロンプトを開き、以下のコマンド群を実行する。
(参考: https://hitco.at/blog/apply-edge-policies-for-non-domain-joined-devices/ )
reg delete HKLM\SOFTWARE\Microsoft\Enrollments\FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF /f reg delete HKLM\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts\FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF /f
Edgeの場合も、基本的には同様の手順となります。
このようにして拡張機能をインストールした所、バックグラウンドのServiceWorkerにおいて、確かにwebRequest
APIを利用できる様子でした4。
開発目的でグループポリシーで拡張機能をインストールした場合のデバッグ
前述の手順で拡張機能をインストールした場合、「ビューを検証」機能が使用できません。 これはグループポリシーで強制インストールされた拡張機能の一般的な制限事項なのですが、デバッグにChromeの開発ツールを利用できないということで、開発段階においてはかなりの痛手となります。
この点は今のところ打開策が無く、この状態での拡張機能のデバッグには、昔ながらのprintデバッグの手法を使うほかないようです。
具体的には、console.log()
のログはデバッグログにも出力されるため、以下のようにしてデバッグログを採取・閲覧することになります。
- Chromeのショートカットをデスクトップ又は任意の場所にコピーする。
- ショートカットを右クリックし、メニューから「プロパティ」を選ぶ。
- リンクターゲット欄にコマンドライン引数
--enable-logging=1
を追加する。 (実行ファイルへのパスとコマンドラインオプションの間にスペースを入れることを忘れないこと。) - 編集したショートカットからChromeを起動する。
%LocalAppData%\Google\Chrome\User Data\chrome_debug.log
の位置に出力されているログを見る。
開発目的でグループポリシーで拡張機能をインストールした場合の設定変更
グループポリシーでインストールされた拡張機能のもう1つの制限事項が、「拡張機能の管理画面からは拡張機能の設定画面に到達できない」という点です。
この点にも打開策が無いため、拡張機能自体に以下のいずれかの変更を加える必要があります。
- 拡張機能自体に「ツールバーのボタンをクリックされたら設定画面をタブで開く」といった形で、設定画面を開く機能を追加する。
- Managed Storageで与えられた設定を反映するように、設定読み込み部分を変更する。
- 拡張機能自体に設定を固定で埋め込む。
まとめ
以上、Chrome(およびEdge)でManifest V3移行後もwebRequest
APIの使用を継続する必要がある拡張機能の開発時の知見をご紹介しました。
webRequest
API自体、いつまで使用し続けられるかは不明となっており、将来的には本記事に記載した手順を使用してもAPIを利用できないことになる可能性は、充分にあり得ます。
その場合、tabs.onUpdated
でURLの変更を検知して、ページ遷移が終わった後のタイミングで処理を行う、といった代替手法5を使う必要があると考えられます。
当社では、本記事でも触れたBrowserSelectorというブラウザー自動切り替えツールを開発・公開しています。 Webブラウザー利用中の場面での、訪問したページのURLやドメインなどをヒントとしたブラウザーの自動切り替えを必要とされている企業のご担当者さまは、どうぞお問い合わせフォームよりお問い合わせ下さい。
また、当社ではWebブラウザーのサポート業務の一環として、Webブラウザーの拡張機能を使用したカスタマイズや、オープンソースのWebブラウザーについてトラブル発生時のソースコードレベルでの調査の実施、対応策の検討などを承っております。 Webブラウザーに導入した拡張機能が期待通りに動作せずお困りの方や、既存の拡張機能に任意の設定を組み込んだ状態で展開したい方も、お問い合わせフォームよりお問い合わせを頂けましたら幸いです。
-
最近になって、実際にManifest V3の正規の方法で実装された広告ブロッカーが公開されたようですが、従来版に比べて機能的な制限が大きい旨が報告されています。 ↩
-
マッチングパターンによる読み込みのブロックまでは行えても、「該当するHTTPリクエストの内容を受け取って別のブラウザーを呼び出す」といった動的な処理を行えないため。 ↩
-
このことはChromiumのイシュートラッカーにも報告されていますが、「WontFix(対応しない)」として閉じられており、今後も状況が変わることはなさそうです。 ↩
-
ただ、ServiceWorkerの動作が停止すると
webRequest
のリスナーも機能しなくなるため、タイマーなどを使って定期的にリスナーを登録し直すようにする必要がある模様です。 ↩ -
この場合、HTTPリクエスト自体は送信されてしまうこと、リダイレクトが行われる前のタイミングには割り込めないこと、埋め込みリソースの読み込みには無力であること、などが制限事項となります。特に、トラフィック削減を目的としていた場合、その効果はほとんど得られなくなってしまうでしょう。 ↩