IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    原来浏览器插件有这么多风险?

    卡颂发表于 2024-03-12 09:51:14
    love 0

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

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

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

    “最近认识个男生,是我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后,用户也不会有任何察觉。

    举个例子,如果闲置Tab是React官网,那恶意网站只需要标题是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,退出所有的账号登录并修改密码。

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



沪ICP备19023445号-2号
友情链接