扩展程序在浏览器中获得特殊权限,因此成为攻击者的理想目标。如果某个扩展程序遭到入侵,该扩展程序的所有用户都可能会受到恶意和不必要的入侵。通过采用以下做法,确保扩展程序的安全性并保护其用户。
保护开发者账号
扩展程序代码需通过 Google 账号上传和更新。如果开发者的账号遭到入侵,攻击者可能会直接向所有用户推送恶意代码。请启用双重验证(最好使用安全密钥)来保护这些账号。
选择性地创建群组
如果使用群组发布功能,请将群组成员仅限于可信开发者。请勿接受不明身份人员提出的加入申请。
永不使用 HTTP
请求或发送数据时,请避免使用 HTTP 连接。假设任何 HTTP 连接都会有窃听者或包含修改内容。应始终优先使用 HTTPS,因为它具有内置的安全功能,可规避大多数中间人攻击。
请求最小权限
Chrome 浏览器会限制扩展程序对在manifest中明确请求的权限的访问权限。扩展程序应仅注册其依赖的 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 的某些部分,或者利用出乎意料的 Web 标准行为(例如命名项)。
- 若要与网页的 DOM 进行交互,内容脚本需要在与网页相同的渲染程序进程中执行。这会使内容脚本容易通过旁边信道攻击(例如,Spectre),以及被攻击者控制(如果恶意网页破坏了渲染程序进程)。
使用敏感数据(例如用户的私密信息)或有权访问浏览器功能的 Chrome API 的操作应在扩展程序的服务工件中执行。避免意外向内容脚本泄露扩展程序权限:
- 假设内容脚本中的消息可能是由攻击者伪造的(例如,验证和清理所有输入,并保护脚本免受跨站点脚本攻击)。
- 假设发送到内容脚本的任何数据都有可能泄露到网页中。请勿向内容脚本发送敏感数据(例如扩展程序中的 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.");
});