确保安全

扩展程序有权访问浏览器中的特殊权限,因此对攻击者来说极具吸引力。如果某个扩展程序遭到入侵,该扩展程序的每位用户都会容易受到恶意和不必要的入侵。采用以下做法,确保扩展程序的安全并保护其用户。

保护开发者账号

扩展程序代码通过 Google 账号上传和更新。如果开发者的账号遭到入侵,攻击者可以直接向所有用户推送恶意代码。启用双重身份验证(最好使用安全密钥)来保护这些账号。

使用适当的成员角色

如果您的发布商有多位成员,请确保授予每位用户的角色都合适。

永不使用 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
}

如果扩展程序需要使用 WebAssembly 或增加对沙盒网页的限制,则可以添加:

{
  "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 中执行。避免意外向内容脚本公开扩展程序权限:

  • 假设来自内容脚本的消息可能是攻击者精心设计的(例如,验证并清理所有输入,并保护您的脚本免受跨站脚本攻击)。
  • 假设发送到内容脚本的任何数据都可能会泄露到网页。请勿将敏感数据(例如扩展程序中的密钥、来自其他 Web 源的数据、浏览记录)发送到内容脚本。
  • 限制可由内容脚本触发的特权操作的范围。不允许内容脚本触发对任意网址的请求或将任意实参传递给扩展程序 API(例如,不允许将任意网址传递给 fetch() 或 browser.tabs.create() 方法)。

注册并清理输入

通过以下方式保护扩展程序免受恶意脚本的侵害:将监听器限制为仅监听扩展程序预期的数据、验证传入数据的发送者,以及清理所有输入。

如果扩展程序需要接收来自外部网站或扩展程序的通信,则应仅注册 runtime.onMessageExternal。请务必验证发件人是否来自可信来源。

// The ID of an external extension
const kFriendlyExtensionId = "iamafriendlyextensionhereisdatas";

browser.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.id === kFriendlyExtensionId)
      doSomething();
});

即使是来自扩展程序本身的 runtime.onMessage 事件中的消息,也应仔细检查,以确保 MessageSender 不是来自遭入侵的内容脚本。

browser.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  if (request.allowedAction)
    console.log("This is an allowed action.");
});