セキュリティの確保

拡張機能はブラウザ内で特別な権限にアクセスできるため、攻撃者にとって格好のターゲットになります。拡張機能が不正使用されると、その拡張機能のすべてのユーザーが悪意のある侵入や望ましくない侵入に対して脆弱になります。これらの手法を取り入れることで、拡張機能のセキュリティとユーザー保護を維持できます。

デベロッパー アカウントを保護する

拡張機能コードは、Google アカウントを通じてアップロードおよび更新されます。デベロッパーのアカウントが侵害された場合、攻撃者が悪意のあるコードをすべてのユーザーに直接 push する可能性があります。これらのアカウントを保護するため、可能であればセキュリティ キーを使用して 2 要素認証プロセスを有効にします。

グループの選択

グループ公開を使用する場合は、信頼できるデベロッパーのみにグループを公開します。知らないユーザーからのメンバーシップ リクエストを受け付けないでください。

HTTP を使用しない

データをリクエストまたは送信する際は、HTTP 接続を使用しないでください。HTTP 接続は盗聴されるか、変更されていることを前提としています。HTTPS には、ほとんどの中間者攻撃を回避する組み込みのセキュリティが組み込まれているため、常に推奨する必要があります。

最小限の権限をリクエストする

Chrome ブラウザは、マニフェストで明示的にリクエストされた権限に対する拡張機能のアクセスを制限します。拡張機能は、依存する API とウェブサイトのみを登録して、権限を最小限に抑える必要があります。

拡張機能の権限を制限することで、潜在的な攻撃者が悪用できるものを制限します。

クロスオリジン fetch()

拡張機能が fetch()XMLHttpRequest() を使用してのみ、拡張機能と権限で指定されたドメインからリソースを取得できます。両方の呼び出しは Service Worker の fetch ハンドラによってインターセプトされます。

{
  "name": "Very Secure Extension",
  "version": "1.0",
  "description": "Example of a Secure Extension",
  "host_permissions": [
    "https://developer.chrome.com/*",
    "https://*.google.com/*"
  ],
  "manifest_version": 3
}

上記のサンプルのこの拡張機能は、権限に "https://developer.chrome.com/*""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://developer.chrome.com/*",
      "https://*.google.com/*"
    ],
    "accepts_tls_channel_id": false
  },
  ...
}

ウェブでアクセス可能なリソース

"web_accessible_resources" でウェブからリソースにアクセスできるようにすると、ウェブサイトや攻撃者が拡張機能を検出できるようになります。

{
  ...
  "web_accessible_resources": [
    {
      "resources": [ "test1.png", "test2.png" ],
      "matches": [ "https://web-accessible-resources-1.glitch.me/*" ]
    }
  ]
  ...
}

Web でアクセス可能なリソースが多いほど、攻撃者が悪用できる手段も増えます。これらのファイルは最小限に抑えてください。

明示的なコンテンツ セキュリティ ポリシーを含める

クロスサイト スクリプティング攻撃を防ぐため、マニフェストに拡張機能のコンテンツ セキュリティ ポリシーを含めます。拡張機能がそれ自体からのみリソースを読み込む場合は、以下を登録します。

{
  "name": "Very Secure Extension",
  "version": "1.0",
  "description": "Example of a Secure Extension",
   "content_security_policy": {
    "extension_pages": "default-src 'self'"
  },
  "manifest_version": 3
}

拡張機能でウェブ アセンブリを使用する必要がある場合や、サンドボックス化されたページの制限を増やす必要がある場合は、次のように追加できます。

{
  "name": "Very Secure Extension",
  "version": "1.0",
  "description": "Example of a Secure Extension",
   "content_security_policy": {
    "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';",
    "sandboxed_pages":"script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
  },

  "manifest_version": 3
}

document.write() と innerHTML を使用しない

document.write()innerHTML を使用して HTML 要素を動的に作成する方が簡単な場合もありますが、拡張機能と拡張機能が依存するウェブページを残すため、攻撃者が悪意のあるスクリプトを挿入する可能性があります。代わりに、手動で DOM ノードを作成し、innerText を使用して動的コンテンツを挿入します。

function constructDOM() {
  let newTitle = document.createElement('h1');
  newTitle.innerText = host;
  document.appendChild(newTitle);
}

コンテンツ スクリプトは慎重に使用する

コンテンツのスクリプト隔離された世界に存在しますが、攻撃から完全に保護されるわけではありません。

  • コンテンツ スクリプトは、ウェブページと直接やり取りする拡張機能の唯一の部分です。このため、悪意のあるウェブページは、コンテンツ スクリプトが依存する DOM の一部を操作することや、名前付きアイテムなどの予期しないウェブ標準の動作を悪用する可能性があります。
  • ウェブページの DOM を操作するには、コンテンツ スクリプトをウェブページと同じレンダラ プロセスで実行する必要があります。このため、コンテンツ スクリプトがサイドチャネル攻撃(Spectre など)が使用されることがあります。また、悪意のあるウェブページによってレンダラ プロセスが侵害された場合に攻撃者に乗っ取られることもあります。

機密データ(ユーザーの個人情報など)や Chrome API を使用してブラウザの機能にアクセスするオペレーションは、拡張機能の Service Worker で実行する必要があります。拡張機能の権限をコンテンツ スクリプトに対して誤って公開しないようにする。

  • コンテンツ スクリプトのメッセージが攻撃者によって作成された可能性があると仮定します(すべての入力を検証してサニタイズし、スクリプトをクロスサイト スクリプティングから保護するなど)。
  • コンテンツのスクリプトに送信されたデータはすべてウェブページに漏洩する可能性があると仮定します。機密データ(拡張機能のシークレット、他のウェブオリジンのデータ、閲覧履歴など)をコンテンツ スクリプトに送信しないでください。
  • コンテンツ スクリプトによってトリガーされる特権操作の範囲を制限する。コンテンツ スクリプトが任意の URL へのリクエストをトリガーしたり、拡張 API に任意の引数を渡したりできないようにします(たとえば、fetch() メソッドや chrome.tabs.create() メソッドに任意の URL を渡すことはできません)。

入力を登録してサニタイズする

悪意のあるスクリプトから拡張機能を保護するため、リスナーを拡張機能が想定しているもののみに制限し、受信データの送信者を検証して、すべての入力をサニタイズします。

拡張機能は、外部のウェブサイトまたは拡張機能からの通信を想定している場合にのみ、runtime.onMessageExternal に登録する必要があります。送信者が信頼できる送信元と一致することを常に検証してください。

// 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.");
});