零站点权限还是全网址通吃:十款爬虫扩展的权限差异对比

最后更新于 August 17, 2026
零站点权限还是全网址通吃:十款爬虫扩展的权限差异对比
AI 摘要
每个 Chrome 扩展都会附带一个 manifest.json,其中声明了它在浏览器层面的能力上限:请求了哪些 API、匹配哪些主机模式、是否注入静态内容脚本、有哪些可选权限,以及允许与哪些外部连接。这是你安装后就能看到的公开文件。但它不能证明运行时代码实际用了哪些声明过的能力、哪些数据离开了本机,或哪些账号访问是通过单独的网页登录完成的。我阅读了这次审计中选出的十款网页抓取和浏览器自动化扩展,包括 Thunderbit —— 也就是我们自己的产品。它们之间的差异非常大。

每个 Chrome 扩展都会自带一个 manifest.json,它基本上决定了扩展在浏览器层面能做到什么:请求了哪些 API、匹配哪些主机、有哪些静态内容脚本、可选权限是什么,以及允许和哪些外部来源建立连接。这个文件是你安装后就能直接看到的公开文件。它不能证明运行时代码实际用了哪些已声明能力、哪些数据离开了本机,或者哪些账号访问是通过单独的网页登录完成的。

我读取了这次审计选中的十个抓取与浏览器自动化扩展,包括 Thunderbit 的扩展——因为这是我们自己的产品。结果差异很大:有的根本没有声明持续的网站访问权限;有的则声明了 13 项权限,其中还包括 clipboardRead。Thunderbit 是这组扩展里唯一声明了 debugger 的扩展,这是一种比较宽泛的 CDP 连接能力,其风险形态和页面访问、OAuth 或用户提供的脚本都不一样。

这并不是在指控什么。某个权限范围很大,往往只是因为要实现对应功能,这是最诚实的做法;而权限很少,也可能只是产品做得更少。关键在于,这些差异非常大,而且是公开的,但从来不会出现在对比表里。

这项分析是怎么做的

每个扩展都是从 Google 自己的更新端点下载成 .crx 文件——也就是 Chrome 本身使用的那个地址——然后解包并解析。没有安装任何扩展,也没有执行任何扩展代码。 这只是对一个 JSON 文件的读取。

下载节奏控制在大约每两秒一次。每个 .crx 文件、它的 SHA-256,以及提取出的 manifest.json 都被保留为分析证据。Thunderbit 和另外九个扩展走的是同一段脚本,不存在特殊通道,所以它的行和其他扩展一样,完全按相同标准得出。

分析使用两类证据,并且将它们分开处理:

  • 声明的静态行为: 主机匹配模式和 content_scripts 条目,包括 matchesrun_atall_frames
  • 运行时代码可用的能力: permissionsoptional_permissions 中列出的 API。它们只说明代码“可以请求或调用什么”,并不意味着它真的会这么做。

这里没有给出“最强”的排序分数。debuggeruserScripts、广泛的主机访问、OAuth 范围、剪贴板访问和外部消息通信,暴露的数据各不相同,触发前提也不同。要比较它们,需要一个这次仅凭 manifest 无法提供的威胁模型。

下面的大小是解包后的总大小,以 MiB(2²⁰ 字节)计算,按 ZIP 条目汇总。

截至 2026-07-29。 扩展会更新;引用前请重新核对。

十个 manifest 都声明了什么

Measured results chart: Declared permission strings

官方参考:Chrome 的权限声明指南

扩展版本解包大小文件数权限数网站访问范围是否可访问 file://
Axiom.ai5.1.037.1 MiB2328http://*/* + https://*/*
Table Capture11.0.4121.1 MiB1154 (+3 个可选权限)<all_urls>
Magical3.119.116.8 MiB39513(+2 个可选权限)<all_urls>
Thunderbit(我们自己的)4.6.415.9 MiB788 个已识别权限(+1 个未识别的数组字符串:commands<all_urls>
Clay for Chrome1.0.06.3 MiB516*://*/*(仅在自有域名注入)
Listly0.9.63.5 MiB847http://*/*https://*/*file:///*.html
Hexomatic1.8.42.7 MiB372仅自有域名
Agenty2.9.72.2 MiB494未声明
Clip to Clay1.8.00.7 MiB1642 个指定域名
TexAu v21.6.60.3 MiB12614 个指定域名

候选名单里还有两个没放进表里,原因值得单独说明。

差异来自设计选择,不是体积差异

Agenty 没有声明任何主机权限,也没有任何内容脚本。 它的 4 个权限是 activeTabscriptingidentityidentity.email。其中 activeTab 是最收敛的:它只会在你点击扩展后,给当前标签页临时权限,而且离开该页面后就失效。也就是说,除非你主动触发,否则它不会在你的页面上运行。整个包体只有 2.2 MiB。

Axiom.ai 声明了 http://*/*https://*/* 并且用匹配 <all_urls> 的内容脚本注入页面;整个扩展解包后是 37.1 MiB、232 个文件——是 Agenty 的 17 倍,而且对你访问的每个页面都拥有持续访问能力。

Hexomatic 和 Agenty 更接近:只有两个权限(storagetabs),没有主机权限,内容脚本也只限制在它自己的两个域名上。

Clay for Chrome 则是另一种形态,值得单独区分:它把 *://*/* 作为主机权限声明出来,但内容脚本只注入它自己的域名。它的持续能力很宽,但自动化行为很窄。单看权限表会把这两者混为一谈。

十个里有五个可以访问你磁盘上的文件

file:/// 不是网站。它是把你本地文件系统渲染在浏览器标签页里的结果——比如你打开的 PDF、HTML 导出文件,或者下载下来的发票。

官方参考:Chrome 匹配模式文档

其中三个扩展明确写了出来。另外两个则是通过别的方式到达的:<all_urls> 包含 file: 协议。

扩展它是如何访问 file://manifest 里是否直接写了 file://出现在哪
Magical在 6 条内容脚本声明里的 4 条中匹配 file:///*——Chrome 能渲染的所有本地文件都能匹配,不只是 HTML内容脚本,以及 web_accessible_resources
Listly匹配 file:///*.html内容脚本
Table Capture通过 <all_urls> 的内容脚本访问,同时它也在 manifest 里直接写了该协议web_accessible_resources
Axiom.ai仅凭 <all_urls> 通配符没有直接写
Thunderbit(我们自己的)仅凭 <all_urls> 通配符没有直接写

http://*/*https://*/* 都不覆盖 file://<all_urls>*://*/* 在这点上也不同。这里的五个扩展,是指它们的声明通过某一种路径或另一种路径覆盖了该协议——这和它们选择了哪种通配符形式没有因果关系。

Chrome 对这一点统一加了一个按扩展单独控制的“允许访问文件网址”开关,默认是关闭的,所以这里的声明只是“申请”,不是自动授予。十个里有五个,这是准确的统计;而且这五个里有两个从来没有在 manifest 里写过 file://:Axiom.ai 和我们自己的 Thunderbit。

这个统计把 web_accessible_resources 也算进去了,而不只是内容脚本和主机权限。Table Capture 在那里明确写了 file://*/*;如果漏掉这一块,就会把它错误归类到“manifest 能访问文件但没有写出协议”的扩展里。

你只有在被请求时才看得见的权限

System diagram: Permissions you can't see until they're requested

optional_permissions 会先在 manifest 里声明,但真正请求要到运行时,所以它们不会出现在安装时弹窗里。只有两个扩展用了它们,而且其中一个很关键。

扩展optional_permissions其中最重要的是
Table CaptureuserScriptsdownloadsidentityuserScripts 在 Chrome 的用户门槛开启后,可以把用户提供的脚本注入页面上下文运行
MagicaldownloadswebRequestwebRequest 可以观察网络流量

userScripts 在被请求之前并不生效,对只看权限数量的人来说它是不可见的。

它还有一个本次审计中其他权限没有的门槛,这一点如果省略就会把它的能力夸大。声明 userScripts 并不等于已经能用它:Chrome 先要求用户做一个明确操作。 在 Chrome 138 之前,这个门槛是全局开启的 Developer Mode,需要在 chrome://extensions 里打开。从 Chrome 138 开始,它变成了扩展详情页上的独立开关 Allow User Scripts,默认关闭。因此,对于普通安装来说,这项能力虽然被声明了,但实际上仍然处于静默状态。更准确地说,在用户启用 Chrome 的门槛后,Table Capture 才能调用 userScripts API。此次审计没有统计有多少用户会去那个设置页,也没有统计有多少人会打开这个开关。

这两项都不隐藏;它们都在 manifest 里。忽略可选块的表格,会低估这两个产品。

注入时机,不只是范围

内容脚本“怎么注入”也很重要,而且会改变整体判断。document_start 是 Chrome 提供的最早钩子;all_frames 会覆盖第三方嵌入内容。

下面列出这组扩展里所有会静态注入到所有 frame 的项目,并按声明时机排序:

扩展run_atall_frames内容脚本匹配模式
Table Capturedocument_start<all_urls>
Listlydocument_startfile:///*.html 加上全部 http 和 https
Axiom.aidocument_start仅自有域名
Clay for Chromedocument_start仅自有域名
Thunderbit(我们自己的)document_end<all_urls>
Magicaldocument_idlefile:///* 加上广泛的 http 和 https
TexAudocument_idle(未设置)十四个指定模式

Table Capture 和 Listly 都用最早的钩子,而且匹配模式很广。Axiom.ai 和 Clay for Chrome 也用了同样的时机,但只在自己域名上注入——时间上同样积极,目标却很窄。

对于静态声明来说,<all_urls> 加上 all_frames 就是匹配范围的上限,而 Table Capture 和 Thunderbit 都在这个上限上。它们声明的时机不同:Table Capture 用的是 document_start;Thunderbit 的静态内容脚本则是 document_end。运行时 API 属于另一类能力,这张表无法推断出来。

权限数量并不是一个好的总结指标。 Table Capture 只声明了 4 项权限——比这里大多数都少——但它却在 <all_urls> 的所有 frame 中于 document_start 注入,并且还可以按需使用 userScripts

谁被允许向扩展发消息

externally_connectable 用来控制哪些网页或其他扩展可以直接向某个扩展的后台脚本发消息。它的默认值其实并不直观。

省略这个键,才是更宽松的设置。 Chrome 在 externally_connectable 缺失时的默认规则是:任何扩展都可以连接,但任何网页都不行。 也就是说,只有你显式声明它,才是在“限制”而不是“放开”。

按这个规则,表格会反过来理解:

扩展externally_connectable 声明谁可以向它发消息
Agenty省略宽松默认值——任何扩展都可以连接,网页不行
Clay for Chrome省略宽松默认值——任何扩展都可以连接,网页不行
Clip to Clay省略宽松默认值——任何扩展都可以连接,网页不行
Listly省略宽松默认值——任何扩展都可以连接,网页不行
Table Capture省略宽松默认值——任何扩展都可以连接,网页不行
TexAu省略宽松默认值——任何扩展都可以连接,网页不行
Thunderbit(我们自己的)省略宽松默认值——任何扩展都可以连接,网页不行
Hexomatic8 个扩展 ID 以及 6 个网页来源从关闭基线同时打开两个通道
Axiom.ai7 个网页来源,没有 ids扩展通道关闭,打开了 7 个网页
Magical{"ids": [], "matches": []}这里唯一一个把两个通道都显式关闭的扩展

Chrome 的规则有两层。根据 manifest 参考文档:

情况谁可以连接
整个键缺失“所有扩展都可以连接,但没有网页可以连接”
键存在,ids 未设置或为空数组 []“没有扩展或应用可以连接”
键存在,matches 未设置或为空数组 []“没有网页可以连接”

更宽松的默认值绑定在整个键缺失这个条件上。一旦这个键存在,这两个子字段默认都先是关闭的,只有写入具体值才会扩大对应通道。

Axiom.ai 只声明了 matches,没有声明 ids 所以它的 ids 处于未设置状态,这意味着没有任何扩展可以向它发消息——扩展通道是关闭的,不是打开的。它打开的是 7 个网页来源,其中只有一个属于 Axiom 自己:两个是无法归属的第三方来源(*://*.tgwc.space/**://*.bitmachine.co.uk/*),其余分别是 localhost0.0.0.0、一个 Google APIs 主机,以及一个它并不运营的大型社交平台。

Hexomatic 把扩展通道打开给了 8 个指定 ID。 由于键已经存在,基线是 0 个扩展;写入 8 个就把可连接扩展数扩到 8。它的 6 个 matches 则把另一个通道从无扩大了,其中两个是通过普通 HTTP 的 http://localhost:8000/*http://localhost:3000/*——用户机器上任何监听这些端口的服务都被列入允许列表。

十个里有七个直接省略了这个键,包括我们自己的 Thunderbit,这七个都处在扩展对扩展消息传递的宽松默认状态。还有两个扩展主动关闭了这个通道:Magical 通过 ids: [] 显式关闭;Axiom.ai 则是声明了这个键,却从不写 ids。而 Magical 还是唯一一个把两个通道都关掉的。

最后这句话,就是为什么要读 manifest,而不是只数权限。一个扩展可以在某个维度上很宽,在另一个维度上却是全组里最严格。

没人统计的那个维度:OAuth 范围

manifest 里可以带一个 oauth2 块,而其中的 scopes 代表你在其他公司的账号访问权限——这和上面所有权限都不是一类能力,单靠权限数量完全反映不出来。

官方参考:Google OAuth 2.0 scope 列表

扩展请求的 oauth2 scopes
Axiom.aiopenidemailprofileauth/driveauth/spreadsheets
Table Captureauth/spreadsheetsauth/userinfo.email
Agentyopenidemailprofile
另外七个,包括我们自己的未声明

https://www.googleapis.com/auth/drive 是范围很大的那个。Google 也提供更窄的 drive.file scope,只允许访问应用自己创建的文件,或者用户明确选择的文件;而 auth/drive 覆盖的是用户整个 Drive 的查看、编辑、新建和删除。auth/spreadsheets 对账号能访问到的每一份表格也是同样的范围。Axiom.ai 和 Table Capture 都把 Google 账号 scope 与 <all_urls> 页面访问权限组合在一起。

不过这张表也有两个限制。scope 是请求,不是自动授予——Google 会显示授权页,用户也可以拒绝,而且扩展可能根本不会调用这些 API。其次,manifest 只能看到通过 Chrome 的 identity 流程完成的 OAuth;如果某个扩展改为把你带到网页登录页,那这里就不会声明任何东西。那七个 0 的意思是“这个文件里没有请求”,不是“它完全无法访问你的 Google 账号”——包括我们自己的 Thunderbit 也是如此,所以这里报告的是这条轴,而不是把它当成“更收敛”的证据。

我们自己的扩展,同一把尺子下

Thunderbit 4.6.4 走的是和另外九个扩展完全相同的 manifest 解析流程。这个包解包后大小是 15.9 MiB,共 78 个文件。

声明的静态行为: host_permissionscontent_scriptsmatches 里都出现了 <all_urls>。静态脚本在 document_endall_frames 中运行。因为 <all_urls> 包含 file:,只要用户开启 Chrome 的文件访问开关,manifest 就可以访问本地文件。Thunderbit 也省略了 externally_connectable,因此按 Chrome 默认规则,任何扩展都可以给它发消息,但网页不行。

运行时能力上限: permissions 数组里有 9 个字符串:activeTabcommandsdebuggeroffscreenscriptingsidePanelstoragetabGroupstabs。Chrome 只把其中 8 个识别为权限;commands 是顶层 manifest 键,放在这个数组里并不会产生效果。Thunderbit 是这组里唯一声明了 debugger 的扩展,它可以把 CDP 连接附加到某个标签页。manifest 还使 scripting 可在运行时注册。这些 API 带来的能力,已经超出了静态的 document_end 那一行;但单靠 manifest 不能证明 Thunderbit 是否真的调用了某个特定 CDP 方法,或者是否在更早的时间点注册过脚本。

这个区分挡住了几种很诱人的、但并不成立的比较。没有更窄的 cookies 权限,并不代表带有 debugger 的代码访问不到某些东西。没有 clipboardRead,也不等于剪贴板完全不可能被触达。反过来说,存在 debugger 也不能证明这些通道真的被使用了。要回答这些问题,需要看源码或者做运行时追踪,而本次并没有做这些。

在这项工具里,Thunderbit 在静态网站访问上比较宽,在这组扩展里又是唯一声明 debugger 的,而且在扩展对扩展消息传递方面保持 Chrome 默认状态。之所以没有“最强”这一说,是因为本审计并没有提供一个可统一比较 CDP、OAuth、userScripts、剪贴板和主机访问的共同威胁模型。

那种不太张扬的设计

TexAu 只有 0.3 MiB——是这里体积最小的,只有一小部分——并且它列出了 14 个具体站点,而不是使用通配符:社交网络、开发者平台、发布平台、聊天产品、商业数据服务,以及它自己的域名。它的内容脚本也精确匹配这 14 个目标。

读这个 manifest,你可以非常准确地知道扩展在哪些地方生效。这其实也是一种产品披露——目标列表比营销文案更直接地说明了工具的用途。

代价也很真实:指定列表无法抓取不在名单上的网站,每增加一个目标都要发布新版本。但“14 个指定域名”和“互联网上所有存在的 URL”完全不是一回事,而且只有前者是清晰可读的。

两个不符合名单说法的产品

Captain Data 的扩展并没有公开分发。 Google 的更新端点对它的扩展 ID 返回的是 HTTP 204 且响应体为空——这就是商店不会匿名提供的内容。而它的 listing 页面则是匿名可访问的:HTTP 200,509,829 字节。抓取结果里看不到版本号、最近更新时间或安装量;脚本备注里也写明了这里的空值证据很弱,而且没有观察到任何登录墙。这个 ID 确实存在,而且是第一方的,所以“仅限链接分发”或“未公开列出”是最合理的解读,但我无法把它和被下架区分开,也不会猜。

Dataflow Kit 根本没有 Chrome 扩展。 它的网站描述的是一个托管 Web 应用,支持点选式选择和 REST API。可它却被放进了一个 Chrome 扩展候选名单里——而这通常就是这类名单的生成方式。

既然都能查,顺带看一下新旧和覆盖范围

商店元数据能提供超出权限之外的产品选择背景。所有扩展的相同字段都在 2026-07-30 被抓取。

扩展商店版本最近更新安装量区间
Thunderbit(我们自己的)4.6.42026-07-28200,000
Listly0.9.62026-07-25100,000
Axiom.ai5.1.02026-07-20100,000
Table Capture11.0.412026-06-26200,000
Magical3.119.12026-04-04200,000
Agenty2.9.72026-02-0810,000
TexAu1.6.62025-08-207,000
Clay for Chrome1.0.02025-04-0910,000
Clip to Clay1.8.02025-04-081,000
Hexomatic1.8.42024-09-063,000
Captain Data未公开提供

有三个产品已经超过一年没更新,Hexomatic 更是快两年了。对扩展来说,这比对库更重要:Chrome 大约每四周就会发一个稳定版,而扩展平台本身也在不断变化。userScripts 在 Chrome 138 里就换了用户门槛;而 2024 年最后一次发布的扩展,面对的规则集和现在浏览器实际执行的规则已经不同了。

这张表还不是哪两件事。安装量是 Google 分级的——1,000 / 3,000 / 7,000 / 10,000 / 100,000 / 200,000——所以它只适合比较数量级,不能更细;而且有些产品在自己的营销里会写更大的数字。日期新,只说明发布得近,不代表维护质量一定更好,也不代表权限风险更低。

还有一个很有用的副产物:在分析过的十个包里,每一个的商店版本都和 manifest 版本一致。 这次审计解析的 CRX 文件,就是商店今天正在提供的版本,不是过时副本。

新鲜度会影响这套选择值不值得进一步排查,但不会改变 manifest 语义。一个去年才更新、而且只写了指定域名的扩展,仍然可能比昨天发布、却使用通配符的扩展暴露更少页面表面。反过来,更新更快的那个包,也可能因为更及时跟进 Chrome 变化而更适合实际使用。做候选筛选时,先用商店日期决定哪些要重新测试,再用 manifest 决定哪些需要更深入的能力审查。不要把这两列合成一个分数。

manifest 不能告诉你的事

已声明的权限只是上限,不是行为。 <all_urls> 只表示扩展可以读取你访问的每一页。它并不意味着它真的会这么做,更不意味着任何东西离开了你的机器。要证明实际发生了什么,需要在运行时观察网络流量——那是另一项工作,这里没有做,所以以上内容都不应被理解为滥用证据。

相关评测:Chrome 扩展可测试性实验

还有三个边界:

  • Chrome 对很多东西都加了门槛。 文件访问默认关闭;activeTab 本身就是刻意收窄的;可选权限需要运行时弹窗;安装时用户会看到权限列表。
  • 广泛权限常常是必要的。 一个任务如果是“从你当前打开的任意页面里提取表格”,那它不可能只靠指定域名白名单完成。范围窄,有时是设计克制,有时只是功能更少。
  • 一个版本,只代表一天。 所有数字都来自 2026-07-29 当天商店正在提供的包。

分析中的关键修正

这份公开统计采用了三条在快速写 manifest 解析器时很容易弄错的规则。第一,<all_urls> 包含 file: 协议,但 Chrome 会把真正的文件访问放在用户控制的开关后面。第二,web_accessible_resources.matches 必须和内容脚本、主机权限一起看;Table Capture 正是在这里明确写出了 file://*/*。第三,externally_connectable 的默认值取决于整个键是缺失,还是键存在但某个子字段为空。上面的表格都一致地应用了这些规则。

Thunderbit 的权限总数也区分了原始字符串和 Chrome 真正识别的权限。它的数组里有 9 项,但 commands 属于顶层键,所以这里采用的有效计数是 8 个已识别权限加 1 个未识别字符串。最后,静态的 content_scripts 声明并不能证明代码调用了 scripting.registerContentScripts 或某个 CDP 方法。这些可能性只会出现在运行时能力里,而不会作为已观察到的行为出现。原始 manifest、CRX 哈希和解析器输出,最好都放进发布附录里,这样读者才能不用相信文字也能复核这些归一化处理。

如果真的要决定安装哪个,至少要把四个维度分开比较:默认会覆盖哪些页面、什么明确的用户操作会解锁更多范围、哪些浏览器或账号 API 会变得可用,以及哪些外部调用方可以向扩展发消息。Agenty 的 activeTab 模式、Table Capture 受门槛控制的 userScripts、Axiom.ai 的 Drive scope、以及 Thunderbit 的 debugger 声明,不是同一条线上的不同点,它们是不同威胁问题的不同答案。

下面这张表把这四种刻意不同的设计放在一起比较:

扩展manifest 中可见的页面范围额外门槛本次审计中的非页面能力外部调用方状态
Agenty没有主机权限,也没有静态内容脚本用户点击后,activeTab 只作用于当前标签页Chrome identity 权限键省略:任何扩展都可连接,网页不行
Table Capturedocument_start 时在所有 frame 中对 <all_urls> 注入静态脚本文件访问默认关闭;userScripts 需要 Chrome 单独的用户门槛可选的 userScriptsdownloadsidentity键省略:任何扩展都可连接,网页不行
Axiom.aiHTTP 和 HTTPS 通配访问;在自有域名上于 document_start 注入静态脚本请求的 Google scopes 需要 OAuth 授权声明了 Drive 和 Sheets OAuth scopes扩展调用通道关闭;打开了 7 个网页来源
Thunderbit<all_urls> 主机访问以及在所有 frame 中于 document_end 注入静态脚本文件访问默认关闭;附加 debugger 受 Chrome 控制且对用户可见声明了 debuggerscriptingtabs 及相关浏览器 API键省略:任何扩展都可连接,网页不行

这张表依然不会给出“赢家”。Agenty 的页面访问很窄,但这并不能说明它的后端怎么处理提交的数据。Axiom.ai 的账号 scope 和扩展读取当前页面不是一类东西。Table Capture 的 userScripts 声明在用户启用单独门槛之前只是静态存在。Thunderbit 的 debugger 权限暴露了很宽的浏览器控制面,但 manifest 并不会告诉你它的代码到底调用了哪些 CDP 域或方法。每一行都告诉你接下来该看什么:运行时网络流量、源码、授权流程,或者浏览器 API 追踪。

同样的区分,在阅读 Chrome 安装提示时也很重要。原始权限数量看不出时机、frame 范围、OAuth scope、web_accessible_resources,也看不出是否省略了 externally_connectable 键。反过来,某个很宽的声明也不能证明它真的在收集或外传数据。manifest 审计最有价值的输出,是一份优先级清晰的运行时测试计划:先识别数据面,再标记用户门槛,然后观察声明出来的路径是否真的被使用。

如何读你自己的

相关评测:浏览器自动化指南

  1. chrome://extensions详情 可以看到已授予的网站访问权限,也能把不需要持续访问的项目切换成 点击时。这会收窄上面讨论的“站点访问”那一半。但它不会影响入站消息传递(externally_connectable 仍然会照常连到 service worker),也不会影响浏览器级权限。Thunderbit 的 debugger 声明在这里尤其重要。Chromium 自己的扩展安全文档指出,debugger API“在某些情况下也可能绕过其他典型限制,例如主机权限或文件访问”,所以把站点访问设成“点击时”,并不能限制它能触达什么。这个开关也不会影响 tabswebNavigationclipboardReaddownloads,或 optional_permissions 里的任何东西。
  2. 对于原始文件,包会位于 Chrome 的 Extensions/<id>/<version>/ 目录下。要看 6 个字段:permissionsoptional_permissionshost_permissionscontent_scripts(里面的 matchesrun_atall_frames)、externally_connectable——记住,缺失这个键对扩展调用方来说是宽松默认值——以及 web_accessible_resources,它的 matches 可能写出内容脚本根本没写的协议。Thunderbit 的最后一个字段里有两个 <all_urls> 条目,向所有来源暴露 index.html 和两个打包脚本,而且 use_dynamic_url: false,这意味着页面可以测试这些稳定的扩展 URL 是否可解析。
  3. 对照当前 Chrome 版本检查商店的最近更新时间。

披露与资源:本文由 Thunderbit 发布,而我们的扩展也被包含在同一张表和同一套解析器中。我们的 开源爬虫总览 覆盖了非扩展类工具。

试用 Thunderbit 进行网页数据提取

简短结论

这十个抓取与自动化扩展——包括我们自己的——都读过了各自的 manifest。

Agenty 不声明网站访问,也没有内容脚本;它只在你点击之后,对当前标签页起作用,包体仅 2.2 MiB。Axiom.ai 声明了所有 HTTP 和 HTTPS URL,整个包体是 37.1 MiB。Magical 声明了 13 项权限,包括 clipboardRead——而且它还是这里唯一一个把入站消息完全关掉的扩展。Table Capture 只声明 4 项权限,却会在 <all_urls> 的所有 frame 中于 document_start 注入脚本——和我们一样都是这个匹配上限,只是它更早注入,而且还可以按需使用 userScriptsTexAu 体积最小,却命中目标最多——跨 13 个不同属性的 14 个模式。它并不是唯一列出目标的:Clip to Clay 声明了两个(clay.com 和一个第三方站点),Hexomatic 和 Clay for Chrome 也都列了自己的域名。TexAu 是唯一一个“列出的多半是别人的网站”的。 十个里有五个可以访问你磁盘上的文件,其中两个——Axiom.ai 和我们自己的——甚至从未在 manifest 里写过 file://

Thunderbit(我们自己的)位于更宽的一端:主机访问和静态注入都覆盖 <all_urls>,另外还声明了 debugger,而这组里没有其他扩展这样做。它处在 Chrome 默认允许任何扩展向它发消息的位置,而且在 Chrome 的文件访问门槛开启后也能触达 file://

声明只是上限,不是行为;这些都不表示存在误用。但它们确实是公开的、免费可查的,而且两端之间的差距,比产品页面上能看到的还要大。

试用 Thunderbit 进行网页数据提取 Get Started Free

常见问题

权限很宽是不是说明这个扩展做了不该做的事——为什么只数权限还不够? 不是,因为只数权限会漏掉两件事。<all_urls> 只表示扩展可能读取你访问的每一页;它并不说明它到底做了什么,也不说明任何东西是否离开了你的机器。而且,一个要从任意页面提取数据的工具,本来就不可能只靠指定域名列表工作。这里发现的是范围差异,不是违规行为——要确认真实行为,必须做运行时流量分析,而这次审计没有做。至于“只数”的问题:注入设置不是权限,所以 Table Capture 只算 4 个权限,但它仍然会在 document_startall_frames<all_urls> 上注入。optional_permissions 也不会出现在安装弹窗里——Table Capture 可以在运行时请求 userScripts,这会允许在页面上下文中运行任意用户脚本,而 Magical 可以请求 webRequest

这里面谁要求最少? Agenty:4 项权限,没有主机权限,也没有内容脚本。它依赖 activeTab,这只会在你点击扩展后、并且只在当前标签页上临时生效。排在后面的是 Hexomatic,只有 2 项权限,内容脚本也只限制在它自己的域名上。

扩展怎么能访问我的本地文件,却又没写 file:// 因为 <all_urls> 包含 file: 协议。Listly、Magical 和 Table Capture 都直接写了 file:// 模式——Magical 写在内容脚本里,Table Capture 写在 web_accessible_resources 里。Axiom.ai 和 Thunderbit 则是通过通配符覆盖到了这一点,完全没写出来。http://*/*https://*/* 都不覆盖 file://。Chrome 会把文件访问默认保持为关闭,需要每个扩展单独切换,所以这里的声明只是“申请”,不是自动放行。

什么是 externally_connectable,为什么省略它反而更宽松? 它指定哪些网页来源或扩展 ID 可以向扩展的后台脚本发消息。Chrome 在这个键缺失时的默认规则是:任何扩展都可以连接,但任何网页都不行。十个里有七个省略了它,包括 Thunderbit。键存在时,Hexomatic 会向 8 个指定 ID 打开扩展通道;Axiom.ai 会向 7 个网页来源开放,但扩展通道保持关闭;Magical 则把两个列表都设为空,从而把两个通道都关掉。

Thunderbit 自己的 manifest 到底声明了什么? <all_urls> 主机访问和静态内容脚本注入,all_framesdocument_end;15.9 MiB、78 个文件;以及权限数组里的 9 个字符串。其中 8 个是 Chrome 可识别的权限:activeTabdebuggeroffscreenscriptingsidePanelstoragetabGroupstabscommands 是顶层 manifest 键,放在这个数组里没有作用。这里没有其他扩展声明 debugger。Thunderbit 也会在 Chrome 的文件访问门槛开启后,通过 <all_urls> 触达 file://,并且省略了 externally_connectable。运行时行为并没有被执行,所以这份审计不会声称它实际调用了哪些 CDP 或脚本方法。

Ke
Ke
Thunderbit 首席技术官 | 高级数据科学家与机器学习专家 Ke Shen 拥有近十年的机器学习和数据科学经验,毕业于哥伦比亚大学,曾任 Walmart Labs 高级数据科学家。他在 Python、R、Java 和统计学方面拥有深厚且备受同行认可的专业能力,并分享如何将复杂的 AI 算法从理论落地到生产级架构的实战经验。
目录
Thunderbit · AI 网页数据代理

一键 内提取任意页面数据

深受 250,000+ 用户信赖
提供免费方案
从网页到表格
描述你的需求——Thunderbit 的 AI 代理会帮你抓取并导出到 Excel、Google Sheets、Airtable 或 Notion。可免费开始。
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week