💭
Chrome拡張機能からページのグローバル変数にアクセスする
背景
Chromeの拡張機能から、対象ページに定義されているグローバル変数にアクセスしたいと思いましたが、その方法を見つけるのに苦労したので、ここに記録しておきます。
前提条件
以下のように、対象ページにwindow.$DATAというグローバル変数が定義されているとします。
このグローバル変数の値をコンソールに出力します。
index.html
<script>
window.$DATA = {"PARAM":test}
</script>
失敗:スクリプトをインジェクトする
./
├──manifest.json
└──content-script.js
manifest.json
{
"manifest_version": 3,
"content_scripts": [
{
"js": [
"content-script.js"
],
"matches": [
"https://*/*"
]
}
]
}
content-script.js
// ページにスクリプトをインジェクトする
const script = document.createElement('script');
script.textContent = `
(function() {
console.log(window.$DATA.PARAM);
})();
`;
document.documentElement.appendChild(script);
script.remove(); // スクリプトをインジェクト後、削除する
こちらの方法では、以下のようなエラーが発生します。
このエラーは、Webページで設定された Content Security Policy (CSP) によって、インラインスクリプトの実行が禁止されているために発生します。
web_accessible_resources
を利用する
成功:./
├──manifest.json
├──content-script.js
└──web_accessible_resources.js
manifest.json
{
"manifest_version": 3,
"content_scripts": [
{
"js": [
"content-script.js"
],
"matches": [
"https://*/*"
]
}
],
"web_accessible_resources": [
{
"resources": [
"web_accessible_resources.js"
],
"matches": [
"https://*/*"
]
}
]
}
content-script.js
const injectScript = (filePath, tag) => {
var node = document.getElementsByTagName(tag)[0];
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', filePath);
node.appendChild(script);
}
injectScript(chrome.runtime.getURL('web_accessible_resources.js'), 'body');
web_accessible_resources.js
console.log(window.$DATA.PARAM);
多くのWebページはCSPを設定しており、インラインスクリプトや外部スクリプトの読み込みを厳密に制御しています。通常、Chrome拡張機能が注入するスクリプトは、このCSPの影響を受けるため、例えば「インラインスクリプト禁止」や「外部リソース制限」によってエラーが発生します。
しかし、web_accessible_resources
によってChrome拡張機能のリソースが正しく公開されると、そのリソースはCSPの制約に反しない形でWebページに読み込まれることができるようになります。これでエラーが発生しなくなります。
参考資料
Discussion