4
头图

嫦美找到我时,整个人是崩溃的 —— “卡颂,我好像被监视了”。

傍晚的星巴克,她的影子被吊灯拉得很长,颤抖着如同她此刻的内心。

“怎么回事?”我尽量让声音听起来平静些。

“最近认识个男生,是我MBA同学,对我很热情,也很懂我”嫦美环顾四周,仿佛随时会有什么东西从夜色中跳出来。

“缘分啊,这不很好嘛?”我笑着说。

“不是那种心有灵犀的懂,是那种生活起居都被监视的懂”嫦美解释道。不待我回应,又补充道:“这次约你出来,也是想让你帮忙看看我电脑有没有被植入啥监听木马”。

说罢,从背包里取出MacBook Air递给我。

“Mac一般安全性都蛮高的,你最近没装啥来路不明的应用吧?”一边摆弄她的电脑,我一边问道。

“我也不会装应用,平时主要就上上网、刷刷剧”。

浏览完她的应用列表,我顺手打开了浏览器,又习惯性打开插件列表。

这时,一个浏览器插件吸引了我的注意:

“这是啥?”

“奥,我们MBA的网课需要在这个平台看。这个平台很严,看课不能快进,也不能切换到其他页面。这是那个男同学发我的,装了后就能突破这些限制,还挺方便”说罢,嫦美皱了皱眉“和这个插件不会有关系吧?”

“不好说,等我看看插件源码”。

事实证明,这个插件真的有问题......

本文参考文章Let's build a Chrome extension that steals everything

免费领取卡颂原创React教程(原价359)、加入人类高质量前端群

浏览器插件能做什么?

浏览器插件为我们上网提供了极大便利,比如:

  • GPT插件能帮我们一键总结网页内容
  • 翻译插件能实时翻译网页内容
  • 去广告插件能去掉网页牛皮癣,还我们清爽的页面

实际上,浏览器插件除了能分析并修改原始页面外,还能:

  • 获取我们的实时位置
  • 读取、修改我们复制粘贴的内容
  • 读取cookie、浏览历史
  • 屏幕截图
  • 记录键盘输入
  • 等等

可以说,有心人只要利用得当,就能通过浏览器插件获得我们上网的所有足迹。

这时,有人会说:“插件能做这些没错,但必须申请必要的权限,我不给他权限不就行了?”

事实真的这么简单么?

安全约束够么?

《Building Browser Extensions》一书作者Matt Frisbie为了演示浏览器插件的潜在安全问题,构造了一个会申请全部49项权限的chrome浏览器插件spy-extension

当你在浏览器安装这个插件后,浏览器确实会提示你插件申请的权限

不过,等等!明明申请了49项权限,这里为什么只显示5项?原来,窗口显示的内容行数有限,超出部分需要拖动滚动条才会显示。

可是,又有几个用户会发现在申请的5项权限下面,滚动条后面还隐藏了44项权限呢

一旦有了权限,想做什么就取决于插件作者的想象力了。可以被用来做坏事的WebExtensions API非常多,比如:

Service Worker

后台运行的Service Worker可以监听发出的网络请求,并在请求发送到网络之前修改它们。

这意味着插件可以使用Service Worker发送数据到服务器,或者在用户浏览网页时拦截请求并发送额外的数据。

由于Service Worker运行于一个独立的后台进程中,所以打开调试工具的Network面板看不到插件发出的请求:

都有哪些有价值的数据可以收集呢?

用户敏感数据

最简单的,监听用户键盘输入:

[...document.querySelectorAll("input,textarea,[contenteditable]")].map((input) =>
  input.addEventListener("input", _.debounce((e) => {
    // 处理 用户输入
  }, 1000))
);

除此之外:

  • chrome.cookies.getAll({})会以数组的形式返回浏览器的所有cookie
  • chrome.history.search({ text: "" })会以数组形式返回用户的整个浏览历史记录
  • chrome.tabs.captureVisibleTab()会静默将用户当前正在查看的页面截图,并以data URL的形式返回。
  • chrome.webRequest可以让插件监控所有Tab的流量

上述API结合Service Worker传输数据,用户在插件作者面前无异于裸奔。

更高阶的玩法

据嫦美表示 —— 她那个MBA同学好像知道她住哪儿,这是怎么做到的呢?很有可能是通过获取地理位置的插件功能。

一个网课插件获取地理位置,这不是太奇怪了么?可是嫦美一点都没发觉,这是怎么办到的?

如果插件脚本获取地理位置(通过navigator.permissions.query({ name: "geolocation" })),将询问用户授权。

但如果被注入脚本的网站已经获得用户的地理位置授权,插件不需要授权就能静默使用对应功能。

举个例子,如果百度地图向你请求获取地理位置的授权,这很合理,你也大概率会同意。

如果恶意插件可以向百度地图注入脚本,当你访问百度地图时,他就不用再获取授权就能访问你的地理位置。

借尸还魂之法

以上所说的所有功能都局限在 —— 插件向已有网站注入脚本。那插件是否能不被察觉的直接打开恶意网站呢?

答案是 —— 可以,我愿称其为借尸还魂之法。

很多朋友都会打开多个浏览器Tab,但常用的可能就是其中几个,剩下的Tab会闲置很长时间。

而这些闲置的Tab就是最好的下手目标。

经常打开很多Tab

首先,插件通过以下代码筛选出闲置的Tab

const tabs = await chrome.tabs.query({
  // 筛选用户当前没使用的Tab
  active: false,
  // 筛选用户没有pin的Tab,pin的Tab使用频率通常比较高
  pinned: false,
  // 不使用有音频的Tab
  audible: false,
  // 使用已经加载完毕的Tab
  status: "complete",
});

// 筛选出闲置Tab
const [idleTab] = tabs.filter(/** ...省略其他筛选条件 **/)

只要恶意网站的标题、图标(favicon)与闲置Tab一致,那么用恶意网站替换闲置Tab后,用户也不会有任何察觉。

举个例子,如果闲置TabReact官网,那恶意网站只需要标题是React,图标是React,即使闲置Tab跳转到恶意网站,从Tab外观上也无法区分。

下面的代码构造了恶意网站的url,其中与闲置Tab一致的标题、图标保存在url searchParams中:

// 将标题、图标保存在searchParams中
const searchParams = new URLSearchParams({
  returnUrl: idleTab.url,
  faviconUrl: idleTab.favIconUrl || "",
  title: idleTab.title || "",
});

const url = `${chrome.runtime.getURL(
  "恶意网站.html"
)}?${searchParams.toString()}`;

恶意网站在url searchParams中取出标题、图标数据,并替换:

// 修改标题
document.title = searchParams.get('title);

// 修改图标
document.querySelector(`link[rel="icon"]`)
  .setAttribute("href", searchParams.get('faviconUrl'));

最后,用恶意网站替换闲置Tab的网站:

await chrome.tabs.update(idleTab.id, {
  url,
  active: false,
});

恶意网站只需要在做完坏事后用户重新点击 闲置Tab 时跳回原来的网站即可。代码如下:

const searchParams = new URL(window.location.href).searchParams;

function useReturnUrl() {
  // 跳回原来网站
  window.location.href = searchParams.get('returnUrl');
}

if (document.visibilityState === "visible") {
  useReturnUrl();
}

// 用户访问了闲置Tab
document.addEventListener("visibilitychange", () => useReturnUrl());

// ...开始做坏事

// 做完坏事,跳回原来网站
useReturnUrl();

从用户的视角看,当他点击闲置Tab时,网站重新加载。对于一个闲置的Tab来说,重新访问时加载页面是再正常不过的逻辑。

只是用户不会知道,这并不是网站重新加载,而是退回到前一个网站

后记

有人会说 —— 我只使用那些信得过的插件。

但今天信得过的插件,明天就一定信得过么?在暗网中,用户量大的免费浏览器插件能卖不错的价钱。

为什么会有人收购这类没有商业价值的免费插件呢?一种可能是 —— 收购后向代码中投毒,只要用户升级插件就会中招。

所以,好用的插件不一定没问题,今天没问题的插件明天也不一定没问题。

对于嫦美来说,技术上能做的只能是删除插件、清除缓存、清除cookie,退出所有的账号登录并修改密码。

但似乎更大的危险,来自现实世界......


卡颂
3.1k 声望16.7k 粉丝