确保安全

扩展程序可以获取浏览器内的特殊权限,因此成为攻击者的有吸引力的目标。如果扩展程序遭到入侵,该扩展程序的每位用户都会受到恶意和不必要的入侵。通过整合这些做法,可以确保扩展程序及其用户的安全。

保护开发者账号

扩展程序代码通过 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 访问资源,网站和攻击者可检测到相应扩展程序。

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

可用的网络资源越多,潜在攻击者利用的途径就越多。请尽量减少这些文件。

包含露骨内容安全政策

在清单中为扩展程序添加内容安全政策,以防止跨站脚本攻击。如果扩展程序仅从自身加载资源,请注册以下内容:

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

如果扩展程序需要使用 Web Assembly,或会增加对沙盒化网页的限制,可以通过以下方式添加:

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

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

注册和清理输入

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

仅当扩展程序要从外部网站或扩展程序进行通信时,才应注册 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.");
});