拡張機能はブラウザ内の特別な権限にアクセスできるため、攻撃者にとって魅力的な標的となります。拡張機能が侵害されると、その拡張機能のすべてのユーザーが、悪意のある望ましくない侵入に対して脆弱になります。これらの方法を取り入れて、拡張機能のセキュリティを確保し、ユーザーを保護してください。
デベロッパー アカウントを保護する
拡張機能のコードは Google アカウントを通じてアップロードおよび更新されます。デベロッパーのアカウントが不正使用された場合、攻撃者は悪意のあるコードをすべてのユーザーに直接プッシュする可能性があります。このようなアカウントを保護するには、デベロッパー アカウントを専用に作成し、2 要素認証(可能であればセキュリティ キーを使用)を有効にします。
グループを限定的にする
グループ公開を使用する場合は、グループを信頼できるデベロッパーのみに限定してください。知らない人からのメンバーシップ リクエストは承認しないでください。
HTTP を使用しない
データをリクエストまたは送信する際は、HTTP 接続を避けてください。HTTP 接続には盗聴者がいるか、変更が含まれていると想定します。HTTPS には、ほとんどの中間者攻撃を回避するセキュリティが組み込まれているため、常に HTTPS を優先する必要があります。
最小限の権限をリクエストする
Chrome ブラウザでは、拡張機能の権限へのアクセスは、マニフェストで明示的にリクエストされた権限に制限されます。拡張機能は、依存する API とウェブサイトのみを登録することで、権限を最小限に抑える必要があります。任意のコードは最小限に抑える必要があります。
拡張機能の権限を制限すると、攻撃者が悪用できる範囲が制限されます。
クロスオリジン XMLHttpRequest
拡張機能は、XMLHttpRequest を使用して、自身と権限で指定されたドメインからリソースを取得することしかできません。
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"permissions": [
"/*",
"https://*.google.com/"
],
"manifest_version": 2
}
この拡張機能は、権限に "/*" と "https://*google.com/" を指定することで、developer.chrome.com と Google のサブドメイン上のすべてのものへのアクセスをリクエストします。拡張機能が不正使用された場合でも、一致パターンを満たすウェブサイトとのみやり取りする権限しか持ちません。攻撃者は "https://user_bank_info.com" にアクセスしたり、"https://malicious_website.com" を操作したりすることはできません。
マニフェスト フィールドを制限する
マニフェストに不要な登録を含めると、脆弱性が生じ、拡張機能がより目立つようになります。マニフェスト フィールドを拡張機能が依存するフィールドに限定し、特定のフィールド登録を行います。
外部から接続可能
externally_connectable フィールドを使用して、拡張機能が情報を交換する外部拡張機能とウェブページを宣言します。拡張機能が外部接続できる相手を信頼できるソースに制限します。
{
"name": "Super Safe Extension",
"externally_connectable": {
"ids": [
"iamafriendlyextensionhereisdatas"
],
"matches": [
"/*",
"https://*google.com/"
],
"accepts_tls_channel_id": false
},
...
}
ウェブアクセス可能なリソース
web_accessible_resources でリソースをウェブからアクセスできるようにすると、ウェブサイトや攻撃者から拡張機能が検出されるようになります。
{
...
"web_accessible_resources": [
"images/*.png",
"style/secure_extension.css",
"script/secure_extension.js"
],
...
}
ウェブ アクセス可能なリソースが多いほど、潜在的な攻撃者が悪用できる経路が増えます。これらのファイルは最小限に抑えます。
明示的なコンテンツ セキュリティ ポリシーを含める
マニフェストに拡張機能のコンテンツ セキュリティ ポリシーを含めて、クロスサイト スクリプティング攻撃を防ぎます。拡張機能が自身のリソースのみを読み込む場合は、次を登録します。
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"content_security_policy": "default-src 'self'"
"manifest_version": 2
}
特定のホストのスクリプトを拡張機能に含める必要がある場合は、次のように含めることができます。
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"content_security_policy": "default-src 'self' https://extension.resource.com"
"manifest_version": 2
}
実行可能 API を避ける
コードを実行する API は、より安全な代替手段に置き換える必要があります。
document.write() と innerHTML
document.write() と innerHTML を使用して HTML 要素を動的に作成する方が簡単かもしれませんが、拡張機能と、拡張機能が依存するウェブページが、攻撃者による悪意のあるスクリプトの挿入に対して脆弱になります。代わりに、DOM ノードを手動で作成し、innerText を使用して動的コンテンツを挿入します。
function constructDOM() {
let newTitle = document.createElement('h1');
newTitle.innerText = host;
document.appendChild(newTitle);
}
eval()
eval() は渡されたコードを実行するため、可能な限り eval() の使用は避けてください。悪意のあるコードが渡される可能性があります。
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// WARNING! Might be evaluating an evil script!
var resp = eval("(" + xhr.responseText + ")");
...
}
}
xhr.send();
代わりに、JSON.parse() などのより安全で高速なメソッドを使用してください。
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// JSON.parse does not evaluate the attacker's scripts.
var resp = JSON.parse(xhr.responseText);
}
}
xhr.send();
コンテンツ スクリプトを慎重に使用する
コンテンツ スクリプトは分離された世界に存在しますが、攻撃の影響を受けないわけではありません。
- コンテンツ スクリプトは、ウェブページと直接やり取りする拡張機能の唯一の部分です。そのため、悪意のあるウェブページは、コンテンツ スクリプトが依存する DOM の一部を操作したり、名前付きアイテムなどの驚くべきウェブ標準の動作を悪用したりする可能性があります。
- ウェブページの DOM を操作するには、コンテンツ スクリプトをウェブページと同じレンダラ プロセスで実行する必要があります。これにより、コンテンツ スクリプトはサイドチャネル攻撃(Spectre など)によるデータ漏洩に対して脆弱になり、悪意のあるウェブページがレンダラ プロセスを侵害した場合、攻撃者に不正使用される可能性があります。
機密性の高い作業は、拡張機能のバックグラウンド スクリプトなどの専用プロセスで実行する必要があります。拡張機能の権限がコンテンツ スクリプトに誤って公開されないようにします。
- コンテンツ スクリプトからのメッセージは攻撃者によって作成された可能性があると想定します(たとえば、すべての入力を検証してサニタイズし、スクリプトをクロスサイト スクリプティングから保護します)。
- コンテンツ スクリプトに送信されたデータはウェブページに漏洩する可能性があると想定してください。センシティブ データ(拡張機能の Secret、ウェブにおけるオリジンのデータ、閲覧履歴など)をコンテンツ スクリプトに送信しないでください。
- コンテンツ スクリプトでトリガーできる特権アクションのスコープを制限します。コンテンツ スクリプトが任意の URL へのリクエストをトリガーしたり、任意の引数を拡張機能 API に渡したりすることを許可しないでください(たとえば、
fetchAPI やchrome.tabs.createAPI に任意の URL を渡すことを許可しないでください)。
入力を登録してサニタイズする
リスナーを拡張機能が想定しているものだけに制限し、受信データの送信者を検証し、すべての入力をサニタイズすることで、悪意のあるスクリプトから拡張機能を保護します。
拡張機能は、外部のウェブサイトまたは拡張機能からの通信を想定している場合にのみ、runtime.onRequestExternal を登録する必要があります。送信者が信頼できるソースと一致することを常に検証します。
// The ID of an external extension
const kFriendlyExtensionId = "iamafriendlyextensionhereisdatas";
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (sender.id === kFriendlyExtensionId)
doSomething();
});
拡張機能自体からの runtime.onMessage イベントを介したメッセージであっても、MessageSender が侵害されたコンテンツ スクリプトからのものでないことを確認するために精査する必要があります。
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.allowedAction)
console.log("This is an allowed action.");
});
拡張機能自体や承認済みのソースからのユーザー入力や受信データをサニタイズすることで、拡張機能が攻撃者のスクリプトを実行するのを防ぎます。実行可能な API を避ける。
function sanitizeInput(input) {
return input.replace(/&/g, '&').replace(/</g, '<').replace(/"/g, '"');
}