每個 Chrome 擴充功能都會附帶一個 manifest.json,其中揭示了它在瀏覽器層級所能觸及的能力邊界:要求哪些 API、可匹配哪些網站模式、是否載入靜態內容腳本、可選權限有哪些,以及允許哪些外部連線。這份檔案公開存在於你安裝的套件中。它不能證明執行時程式實際用了哪些已宣告的能力、資料是否離開本機,或是否有透過另一個網站登入來存取帳號。
我讀取了這次審核所選的十個網頁爬蟲與瀏覽器自動化擴充功能的 manifest,包括 Thunderbit 的版本,因為那是我們自己的產品。這些擴充功能的差異非常大。有一個完全沒有宣告常駐站點存取;另一個則宣告了 13 項權限,還包含 clipboardRead。Thunderbit 是這組裡唯一宣告 debugger 的擴充功能,這代表它可附加 CDP,風險輪廓和頁面存取、OAuth 或使用者自行提供的腳本都不一樣。
這些都不是指控。廣泛的權限宣告,很多時候只是為了實現某個功能所必須付出的誠實代價;而權限較少,也可能只是代表產品本來就做得比較少。重點是:這種差異非常大,而且是公開可查的,但它從來不會被放進比較表裡。
這項分析怎麼做的
每個擴充功能都是從 Google 自家的更新端點下載成 .crx 檔——也就是 Chrome 本身使用的同一個 URL——接著解包並解析。**沒有安裝任何擴充功能,也沒有執行任何擴充功能程式碼。**這只是對一個 JSON 檔案的閱讀。
下載節奏大約是每兩秒一筆。每個 .crx、其 SHA-256,以及解出的 manifest.json 都被保留為證據。Thunderbit 也和另外九個擴充功能一樣走同一套腳本,不是走特別通道,所以它的那一列和其他產品是用完全相同的方法得出的。
這份分析使用兩類證據,並將兩者分開處理:
- 已宣告的靜態行為: host pattern 與
content_scripts項目,包括matches、run_at和all_frames。 - 執行時程式可用的能力:
permissions或optional_permissions裡列出的 API。這些宣告只代表程式可能請求或呼叫哪些能力,不代表它真的有這麼做。
這裡沒有指定任何「最強」的排序。debugger、userScripts、廣泛的 host 存取、OAuth scope、剪貼簿存取,以及外部訊息傳遞,暴露的是不同類型的資料,也需要不同的前置條件。要比較它們,必須先有一套威脅模型,而這種只看 manifest 的審核並沒有提供。
下方數字都是解包後的總大小,以 MiB(2²⁰ bytes)計算,並依 ZIP entry 加總。
截至 2026-07-29。 擴充功能會更新;引用前請重新檢查。
十個 manifest 各自宣告了什麼

官方參考資料:Chrome 權限宣告指南。
| 擴充功能 | 版本 | 解包後大小 | 檔案數 | 權限數 | 網站存取範圍 | 可觸及 file:// |
|---|---|---|---|---|---|---|
| Axiom.ai | 5.1.0 | 37.1 MiB | 232 | 8 | http://*/* + https://*/* | ✅ |
| Table Capture | 11.0.41 | 21.1 MiB | 115 | 4 (+3 個可選) | <all_urls> | ✅ |
| Magical | 3.119.1 | 16.8 MiB | 395 | 13(+2 個可選) | <all_urls> | ✅ |
| Thunderbit(我們的) | 4.6.4 | 15.9 MiB | 78 | 8 個已識別(+1 個未識別的陣列字串:commands) | <all_urls> | ✅ |
| Clay for Chrome | 1.0.0 | 6.3 MiB | 51 | 6 | *://*/*(僅在自家網域注入) | — |
| Listly | 0.9.6 | 3.5 MiB | 84 | 7 | http://*/*、https://*/*、file:///*.html | ✅ |
| Hexomatic | 1.8.4 | 2.7 MiB | 37 | 2 | 僅自家網域 | — |
| Agenty | 2.9.7 | 2.2 MiB | 49 | 4 | 未宣告 | — |
| Clip to Clay | 1.8.0 | 0.7 MiB | 16 | 4 | 2 個指定網域 | — |
| TexAu v2 | 1.6.6 | 0.3 MiB | 12 | 6 | 14 個指定網域 | — |
另外還有兩個原本在候選清單中,但因為各自值得單獨說明,所以沒有放進表格。
差異是設計選擇,不是大小造成的
**Agenty 沒有宣告任何 host 權限,也完全沒有內容腳本。**它的四個權限是 activeTab、scripting、identity 和 identity.email。activeTab 是比較窄的那一種:它只在你點擊擴充功能後,才授予目前分頁的存取權,而且只持續到你離開該頁面為止。若你不主動呼叫,頁面上什麼都不會執行。它的大小是 2.2 MiB。
Axiom.ai 則宣告了 http://*/* 與 https://*/*,並以 <all_urls> 匹配注入內容腳本,解包後 37.1 MiB、共 232 個檔案——是 Agenty 的 17 倍,而且對你造訪的每一個頁面都有常駐存取權。
Hexomatic 和 Agenty 比較接近:只有兩個權限(storage、tabs),沒有 host 權限,內容腳本也只限制在它自己的兩個網域。
Clay for Chrome 則是第三種型態,值得另外區分:它把 *://*/* 當作 host 權限,但內容腳本只注入自家網域。它的常駐能力很廣,但自動化行為很窄。只看權限表,這兩件事會被混在一起。
十個裡面有五個能碰到你電腦上的檔案
file:/// 不是網站。它是把你的本機檔案系統以瀏覽器分頁形式呈現出來的內容——你打開的 PDF、HTML 匯出檔、下載的發票都算。
官方參考資料:Chrome match pattern 文件。
其中三個擴充功能明確寫了這件事。另兩個則是沒有明寫,但一樣能到達:<all_urls> 本來就包含 file: scheme。
| 擴充功能 | 它如何觸及 file:// | manifest 裡是否明寫 file://? | 位置 |
|---|---|---|---|
| Magical | 在六個內容腳本項目中的四個,匹配 file:///*——Chrome 會渲染的所有本機檔案,不只 HTML | ✅ | 內容腳本,以及 web_accessible_resources |
| Listly | 匹配 file:///*.html | ✅ | 內容腳本 |
| Table Capture | 透過 <all_urls> 內容腳本,且它也有明寫這個 scheme | ✅ | web_accessible_resources |
| Axiom.ai | 純粹因為用了 <all_urls> 萬用字元 | — | 沒有明寫 |
| Thunderbit(我們的) | 純粹因為用了 <all_urls> 萬用字元 | — | 沒有明寫 |
http://*/* 與 https://*/* 不涵蓋 file://;<all_urls> 與 *://*/* 在這點上也不同。這裡列出的五個,是因為它們的宣告透過某種路徑碰到了這個 scheme——不是因為它們用了哪種萬用字元就必然如此。
Chrome 會把這件事放在每個擴充功能各自的「Allow access to file URLs」開關底下,而且預設是關閉的,所以這份宣告只是請求,不是直接授權。五個中的五個是誠實的計數,而其中兩個甚至從頭到尾都沒在 manifest 裡寫過 file://:Axiom.ai 和我們自己的 Thunderbit。
這個計數包含 web_accessible_resources,不只是內容腳本與 host 權限。Table Capture 在那裡明寫了 file://*/*;如果漏看這一段,就會錯把它歸到那些沒有明寫 scheme、但 manifest 仍可觸及本機檔案的擴充功能裡。
你看不到、但它們可在執行時才要求的權限

optional_permissions 會先在 manifest 中宣告,但要到執行時才請求,因此不會出現在安裝時的權限提示裡。這次有兩個擴充功能使用了它,而其中一個相當重要。
| 擴充功能 | optional_permissions | 真正重要的是哪一個 |
|---|---|---|
| Table Capture | userScripts、downloads、identity | 啟用 Chrome 的使用者門檻後,userScripts 可在頁面情境中執行使用者提供的腳本 |
| Magical | downloads、webRequest | webRequest 會觀察網路流量 |
userScripts 在被請求之前是不存在的,而且對任何只會看權限數字的人來說,它是看不見的。
它還有一個這次審核中其他權限沒有的門檻,如果不把這點說明清楚,就會高估它的能力。要使用 userScripts,不只是宣告就夠了:Chrome 會先要求明確的使用者動作。 在 Chrome 138 之前,這個門檻是全域開關的 Developer Mode,要在 chrome://extensions 中開啟。從 Chrome 138 起,變成該擴充功能詳細頁上的「Allow User Scripts」獨立切換,且預設關閉。所以對一般安裝而言,這項能力是被宣告了,但實際上沒有啟用。最精確的說法是:使用者先打開 Chrome 的門檻後,Table Capture 才能讓 userScripts API 可用。本次審核沒有量測有多少使用者會去打開那個設定或切換開關。
這兩者都不是隱藏起來的;都寫在 manifest 裡。若忽略 optional 區塊,會低估這兩個產品。
不只看範圍,也要看注入時間
內容腳本怎麼注入,常常被忽略,但它會改變整體圖景。document_start 是 Chrome 提供的最早掛鉤;all_frames 會涵蓋第三方嵌入框架。
以下是這組裡所有靜態注入到所有 frame 的項目,依宣告時間排序:
| 擴充功能 | run_at | all_frames | 內容腳本匹配模式 |
|---|---|---|---|
| Table Capture | document_start | ✅ | <all_urls> |
| Listly | document_start | ✅ | file:///*.html 加上所有 http 與 https |
| Axiom.ai | document_start | ✅ | 僅自家網域 |
| Clay for Chrome | document_start | ✅ | 僅自家網域 |
| Thunderbit(我們的) | document_end | ✅ | <all_urls> |
| Magical | document_idle | ✅ | file:///* 加上廣泛的 http 與 https |
| TexAu | document_idle(未設定) | ✅ | 十四個指定模式 |
Table Capture 與 Listly 都是在廣泛匹配模式下,用最早的掛鉤時機注入。Axiom.ai 和 Clay for Chrome 也是同樣的時間點,但只在它們自己的網域上使用—— aggressiveness 一樣,目標範圍較窄。
對靜態宣告來說,<all_urls> 加上 all_frames 就是匹配廣度的上限,而 Table Capture 與 Thunderbit 都在這個上限上。兩者的宣告時間不同:Table Capture 用的是 document_start;Thunderbit 的靜態內容腳本則是 document_end。執行時 API 是另一個能力類別,不能從這張表直接推論。
只看權限數是很差的摘要統計。 Table Capture 只宣告四個權限——比這裡大多數都少——但它卻在 <all_urls> 上,以 document_start、對所有 frames 注入,並在需要時還能用 userScripts。
誰可以向這個擴充功能送訊息
externally_connectable 控制哪些網頁或其他擴充功能,可以直接向擴充功能的背景腳本送訊息。它的預設值很反直覺。
如果把這個鍵整個省略,反而是較寬鬆的設定。 Chrome 的預設行為是:當 externally_connectable 不存在時,任何擴充功能都可以連線,但任何網頁都不行。 如果你有明寫這個鍵,才是在限制它。
照這個規則來看,表格就會翻轉:
| 擴充功能 | externally_connectable 宣告 | 誰可以向它送訊息 |
|---|---|---|
| Agenty | 省略 | 寬鬆預設——任何擴充功能都可連線,任何網頁都不行 |
| Clay for Chrome | 省略 | 寬鬆預設——任何擴充功能都可連線,任何網頁都不行 |
| Clip to Clay | 省略 | 寬鬆預設——任何擴充功能都可連線,任何網頁都不行 |
| Listly | 省略 | 寬鬆預設——任何擴充功能都可連線,任何網頁都不行 |
| Table Capture | 省略 | 寬鬆預設——任何擴充功能都可連線,任何網頁都不行 |
| TexAu | 省略 | 寬鬆預設——任何擴充功能都可連線,任何網頁都不行 |
| Thunderbit(我們的) | 省略 | 寬鬆預設——任何擴充功能都可連線,任何網頁都不行 |
| Hexomatic | 八個擴充功能 ID 與 六個 web origin | 從封閉基線打開兩條通道 |
| Axiom.ai | 七個 web origin,沒有 ids | 擴充功能通道關閉,開放了七個網頁 |
| Magical | {"ids": [], "matches": []} | 這裡唯一同時明確關閉兩條通道的擴充功能 |
Chrome 的規則有兩層。以下摘自 manifest 參考文件:
| 情況 | 誰可以連線 |
|---|---|
| 整個鍵 不存在 | 「所有擴充功能都可以連線,但沒有網頁可以連線」 |
鍵存在,ids 未設定或為 [] | 「沒有任何擴充功能或應用程式可以連線」 |
鍵存在,matches 未設定或為 [] | 「沒有任何網頁可以連線」 |
所謂寬鬆預設,取決於整個鍵都不存在。一旦這個鍵存在,兩個子欄位都會先預設關閉,只有在指定值後才會把各自通道打開。
Axiom.ai 只宣告了 matches,沒有宣告 ids。 這代表它的 ids 是未設定狀態,也就是說沒有任何擴充功能能對它送訊息——擴充功能通道是關閉的,不是打開的。它真正打開的是七個 web origin,其中只有一個是 Axiom 自家網域:兩個是無法直接歸屬的第三方 (*://*.tgwc.space/*、*://*.bitmachine.co.uk/*),其餘則是 localhost、0.0.0.0、一個 Google APIs 主機,以及一個它並不營運的大型社群平台。
Hexomatic 把擴充功能通道開給八個指定 ID。 在鍵存在的前提下,基線是零個擴充功能;指定八個之後就變成八個。它的六個 matches 也把另一條通道從無擴大到有,而其中兩個是透過明文 HTTP 的 http://localhost:8000/* 與 http://localhost:3000/*——只要使用者機器上有任何服務在這些連接埠回應,都會被納入 allowlist。
十個裡有七個完全省略這個鍵,包括我們自己的 Thunderbit,而這七個都落在擴充功能對擴充功能訊息傳遞的寬鬆預設上。另有兩個擴充功能把這條通道關掉:Magical 用 ids: [] 明確關閉;Axiom.ai 則是宣告了這個鍵,但從未提到 ids。Magical 是唯一一個把兩條通道都關掉的。
最後這一點,就是為什麼要讀 manifest,而不是只數權限。同一個擴充功能,可能在某個面向非常寬,在另一個面向卻是這組裡最嚴格的。
沒人會統計的那個軸:OAuth scopes
manifest 可以包含 oauth2 區塊,而裡面的 scopes 代表你對其他公司的帳號授權——這和前面那些能力是不同層次的存取範圍,而且沒有任何權限數字能反映出來。
官方參考資料:Google OAuth 2.0 scope 清單。
| 擴充功能 | 要求的 oauth2 scopes |
|---|---|
| Axiom.ai | openid、email、profile、auth/drive、auth/spreadsheets |
| Table Capture | auth/spreadsheets、auth/userinfo.email |
| Agenty | openid、email、profile |
| 其餘七個,包括我們的 | 未宣告 |
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;如果某個擴充功能是把你導到網站登入頁,它在這裡就不會寫任何東西。那七個零只代表「這個檔案裡沒有請求」,不是「沒有存取你的 Google 帳號」——包括我們自己的 Thunderbit 也是,所以這個軸是報告出來,而不是拿來主張它很窄。
我們自己的擴充功能,放在同一把尺上看
Thunderbit 4.6.4 也走了和另外九個相同的 manifest 解析器。這個套件解包後是 15.9 MiB,共 78 個檔案。
已宣告的靜態行為: host_permissions 與內容腳本匹配裡都出現了 <all_urls>。靜態腳本會在 all_frames、document_end 執行。由於 <all_urls> 包含 file:,在使用者打開 Chrome 的檔案存取開關後,manifest 就能觸及本機檔案。Thunderbit 也省略了 externally_connectable,所以 Chrome 的預設允許任何擴充功能送訊息,但不允許任何網頁。
執行時能力上限: permissions 陣列中有九個字串:activeTab、commands、debugger、offscreen、scripting、sidePanel、storage、tabGroups 和 tabs。Chrome 會把其中八個識別為權限;commands 是頂層 manifest key,放進這個陣列裡不會產生效果。Thunderbit 是這組裡唯一宣告 debugger 的擴充功能,它可以把 CDP 附加到分頁上。manifest 也讓 scripting 可供執行時註冊使用。這些 API 所形成的能力,超出了靜態 document_end 那一列所能表達的範圍;但只讀 manifest 不能證明 Thunderbit 有呼叫特定 CDP method,也不能證明它有在更早的某個時間點註冊腳本。
這個區分也阻止了幾個很誘人、但其實無效的比較。沒有更窄的 cookies 權限,並不能限制有 debugger 的程式可能讀到什麼。沒有 clipboardRead,也不代表一定無法接觸剪貼簿。反過來說,宣告了 debugger 也不等於真的有用到那些路徑。要回答這些問題,得看原始碼或做執行時追蹤;這兩件事這次都沒做。
在這項工具上,Thunderbit 對靜態站點存取很寬,在這組裡又是唯一宣告 debugger 的,而且對擴充功能之間的訊息傳遞維持 Chrome 的預設。沒有任何單一的「最強」排名,因為這份審核沒有提供能同時涵蓋 CDP、OAuth、userScripts、剪貼簿與 host 存取的共同威脅模型。
這種不被行銷的克制設計
TexAu 只有 0.3 MiB——是這裡最小的,約只有第二小的一半——而且它不是用萬用字元,而是明確列出 14 個特定站點:社群網路、開發者平台、內容發布平台、聊天產品、商業資料供應商,以及它自己的網域。它的內容腳本也精準匹配同樣的 14 個目標。
你可以直接讀這份 manifest,知道這個擴充功能會在哪些地方運作。這同時也是一種產品揭露——它列出的目標,比行銷文案更直白地說明了這個工具是拿來做什麼的。
代價也是真實的:名單式設計無法抓取不在清單上的網站,每增加一個目標都要發版。但「14 個指定網域」和「任何存在的 URL」是完全不同的概念,而只有前者是可讀的。
兩個產品,原本的清單說得不對
Captain Data 的擴充功能沒有公開散佈。 Google 的更新端點對它的擴充功能 ID 回傳的是 HTTP 204 且空白內容——這通常代表商店不會匿名提供這個東西。相對地,它的 listing 頁面卻可以匿名取得:HTTP 200、509,829 bytes。抓取結果無法從中找到版本字串、最後更新日期或安裝數;腳本自己的註記也說,那裡為 null 只能算弱證據,而且沒有觀察到登入牆。這個 ID 是真實且第一方的,所以最可能的解讀是只限連結存取或未列出散佈;但我無法區分這和下架之間的差別,也不會瞎猜。
Dataflow Kit 根本沒有 Chrome 擴充功能。 它的網站描述的是一個有點選式選取與 REST API 的託管網頁應用。它原本卻還是被放進 Chrome 擴充功能的候選清單裡——這通常就是這類清單會怎麼做出來的。
就算只是免費可以查的資訊,也要看新鮮度與覆蓋範圍
商店的中繼資料,除了權限之外,也提供產品選擇脈絡。相同欄位在 2026-07-30 為每個擴充功能都被擷取了一次。
| 擴充功能 | 商店版本 | 最後更新 | 安裝量級 |
|---|---|---|---|
| Thunderbit(我們的) | 4.6.4 | 2026 年 7 月 28 日 | 200,000 |
| Listly | 0.9.6 | 2026 年 7 月 25 日 | 100,000 |
| Axiom.ai | 5.1.0 | 2026 年 7 月 20 日 | 100,000 |
| Table Capture | 11.0.41 | 2026 年 6 月 26 日 | 200,000 |
| Magical | 3.119.1 | 2026 年 4 月 4 日 | 200,000 |
| Agenty | 2.9.7 | 2026 年 2 月 8 日 | 10,000 |
| TexAu | 1.6.6 | 2025 年 8 月 20 日 | 7,000 |
| Clay for Chrome | 1.0.0 | 2025 年 4 月 9 日 | 10,000 |
| Clip to Clay | 1.8.0 | 2025 年 4 月 8 日 | 1,000 |
| Hexomatic | 1.8.4 | 2024 年 9 月 6 日 | 3,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 變動,它在實務上也可能是比較好的選擇。做 shortlist 時,先用商店日期決定哪些要重測,再用 manifest 判斷哪些需要更深入的能力審查。不要把這兩欄硬合成一個分數。
manifest 不會告訴你的事
已宣告的權限只是上限,不是行為本身。 <all_urls> 代表擴充功能可以讀取你造訪的每個頁面;它並不表示真的有這樣做,也不代表任何資料一定會離開你的裝置。要確認真實發生了什麼,必須在執行時觀察網路流量——那是不同的工作,這裡沒有做;因此,上面任何內容都不應被解讀為濫用證據。
相關審查:Chrome 擴充功能可測試性實驗。
還有三個界線:
- Chrome 本身會限制很多事情。 檔案存取預設關閉;
activeTab故意設得很窄;可選權限需要執行時提示;使用者在安裝時會看到權限清單。 - 廣泛權限常常是必要的。 一個工作目標是「從你目前看到的任何頁面擷取表格」的工具,不可能只靠指定網域 allowlist 運作。範圍窄,有時是紀律;有時只是產品功能比較少。
- 一個版本,只代表一天。 每一個數字都來自 2026-07-29 當天提供的套件。
分析中的重要修正
這些公開數字用了三個很容易在快速寫 manifest parser 時弄錯的規則。第一,<all_urls> 包含 file: scheme,但 Chrome 仍把真正的檔案存取放在使用者可控的開關後面。第二,web_accessible_resources.matches 必須和內容腳本與 host 權限一起看;Table Capture 就是在那裡明確寫了 file://*/*。第三,externally_connectable 的預設值,取決於整個鍵是否缺失,或是鍵存在但某個子欄位是空的。上面的表格都是一致地依照這些規則處理。
Thunderbit 的權限總數,也有把原始字串和 Chrome 可識別權限區分開來。它的陣列裡有九個項目,但 commands 屬於頂層鍵,所以這裡實際採用的是八個已識別權限,加上一個未識別字串。最後,靜態 content_scripts 宣告,並不代表程式真的呼叫了 scripting.registerContentScripts 或某個 CDP method。這些可能性只屬於執行時能力,而不是已觀察到的行為。原始 manifest、CRX 雜湊與 parser 輸出,才是這些標準化結果的審計軌跡,因此讀者不需要只靠文意來相信它。
如果真的要做安裝決策,至少要分開比較四個面向:預設哪些頁面在範圍內、哪些明確的使用者動作會解鎖更大範圍、哪些瀏覽器或帳號 API 會變得可用,以及哪些外部呼叫者能向擴充功能送訊息。Agenty 的 activeTab 模式、Table Capture 受門檻控制的 userScripts、Axiom.ai 的 Drive scope,以及 Thunderbit 的 debugger 宣告,都不是同一條線上的不同點;它們是在回答不同的威脅問題。
以下是把這四種刻意不同的設計放在一起比較:
| 擴充功能 | manifest 中可見的頁面範圍 | 額外門檻 | 本次審核中的非頁面能力 | 外部呼叫者狀態 |
|---|---|---|---|---|
| Agenty | 沒有 host 權限,也沒有靜態內容腳本 | 使用者在目前分頁點擊 activeTab | Chrome identity 權限 | 鍵省略:任何擴充功能都可連線,任何網頁都不行 |
| Table Capture | 在 <all_urls> 的所有 frames 中,於 document_start 注入靜態腳本 | 檔案存取預設關閉;userScripts 需要 Chrome 的獨立使用者門檻 | 可選 userScripts、downloads、identity | 鍵省略:任何擴充功能都可連線,任何網頁都不行 |
| Axiom.ai | HTTP 與 HTTPS 萬用存取;在自家網域以 document_start 注入靜態腳本 | 針對所請求的 Google scopes 進行 OAuth 同意 | 已宣告的 Drive 與 Sheets OAuth scopes | 擴充功能呼叫者關閉;開放七個 web origins |
| Thunderbit | <all_urls> host 存取,且在所有 frames 中以 document_end 注入靜態腳本 | 檔案存取預設關閉;附加 debugger 具有 Chrome 控管的使用者可見行為 | 已宣告 debugger、scripting、tabs 與相關瀏覽器 API | 鍵省略:任何擴充功能都可連線,任何網頁都不行 |
這張表還是無法得出誰最好。Agenty 的常駐頁面存取很窄,並不代表它後端對送出的資料做了什麼。Axiom.ai 的帳號 scopes 也不能和讀取目前頁面的擴充功能直接相比。Table Capture 的 userScripts 宣告,直到使用者啟用它自己的獨立門檻前都只是無效宣告。Thunderbit 的 debugger 權限暴露了很廣的瀏覽器控制面,但 manifest 沒有透露它實際呼叫哪些 CDP domains 或 methods。每一列真正告訴你的是下一步要看什麼:執行時網路流量、原始碼、同意流程,或瀏覽器 API trace。

同樣的切分,在閱讀 Chrome 的安裝提示時也很重要。單看權限數,無法反映時機、frame 範圍、OAuth scope、web_accessible_resources,或被省略的 externally_connectable 鍵。反過來說,一個廣泛宣告也不等於真的有蒐集或外傳。manifest 審核真正有用的輸出,是一份優先排序過的執行時測試計畫:先辨識資料面,標記使用者門檻,再觀察宣告的路徑是否真的被使用。
如何讀自己的 manifest
相關審查:瀏覽器自動化指南。
chrome://extensions→ Details 會顯示已授權的網站存取範圍,也能把不需要常駐存取的項目切成 on click。這會縮小上面提到的站點存取那一半,但不會影響進來的訊息傳遞(externally_connectable仍會照樣觸及 service worker),也不會影響瀏覽器層級權限。 Thunderbit 的debugger宣告在這裡特別重要。Chromium 自己的擴充功能安全文件說,debugger API「在某些情況下也可能繞過其他典型限制,例如 host 權限或檔案存取」,所以把 site access 設成「on click」並不能限制它可觸及的範圍。這個控制也不會影響tabs、webNavigation、clipboardRead、downloads,或optional_permissions裡的任何項目。- 原始檔位在 Chrome 的
Extensions/<id>/<version>/目錄下。請讀六個欄位:permissions、optional_permissions、host_permissions、content_scripts(其中的matches、run_at、all_frames)、externally_connectable——記得缺失這個鍵時,對擴充功能呼叫者是寬鬆的——以及web_accessible_resources,其中的matches可以指定內容腳本未曾列出的 scheme。Thunderbit 的最後一欄有兩個<all_urls>項目,把index.html與兩個打包腳本暴露給所有 origin,且use_dynamic_url: false,這讓頁面能測試那些固定的 extension URL 是否可解析。 - 將 listing 的最後更新日期和目前 Chrome 版本比對。
揭露與資源:這篇文章由 Thunderbit 發布,而它自己的擴充功能也被納入同一份表格與 parser 中。我們的 開源爬蟲主題頁 涵蓋非擴充功能工具。
簡短版結論
十個爬蟲與自動化擴充功能,包含我們自己的版本,都可以從各自的 manifest 讀出來。
Agenty 沒有宣告站點存取,也沒有內容腳本;你點擊它時,只會在你正在看的分頁上運作,大小是 2.2 MiB。Axiom.ai 宣告了所有 HTTP 與 HTTPS URL,整體達 37.1 MiB。Magical 宣告了 13 項權限,包括 clipboardRead——而且它也是這裡唯一完全關閉進入訊息傳遞的擴充功能。Table Capture 只宣告四個權限,但它在 <all_urls> 上、以 document_start、注入所有 frames——和我們一樣達到匹配上限,只是更早,而且還能在需要時使用 userScripts。TexAu 是最小的,也是列出目標最多的——14 個模式,分散在 13 個不同屬性上。它並不是唯一列出目標的:Clip to Clay 有兩個(clay.com 與一個第三方站點),Hexomatic 和 Clay for Chrome 也列出自己的網域。TexAu 是這些裡唯一一個主要列別人網站清單的。 十個裡有五個能觸及你電腦上的檔案,其中兩個——Axiom.ai 和我們自己的 Thunderbit——甚至從頭到尾都沒寫過 file://。
Thunderbit,我們自己的版本,位在較廣的一端:host 存取與靜態注入都用 <all_urls>,再加上這組裡其他擴充功能都沒宣告的 debugger。它也維持 Chrome 的預設值,允許任何擴充功能送訊息,而且在 Chrome 的檔案存取門檻啟用後,也能觸及 file://。
宣告是上限,不是行為,而這些內容也沒有顯示任何濫用。但它們是公開的、可免費檢查的,而且兩端之間的差距,比產品頁面上看起來大得多。
立即試用 Thunderbit 進行網頁資料擷取 Get Started Free
常見問題
廣泛權限是否代表擴充功能有問題?為什麼只看權限數不夠?
不代表,而且單看數量會漏掉兩件事。<all_urls> 只表示擴充功能可以讀取你造訪的每個頁面;它不說明它到底做了什麼,也不代表任何資料會離開你的裝置。真正要建立任何行為結論,得看執行時網路流量,而這次審核沒有做。另外,計數本身也不完整:注入設定不是權限,所以 Table Capture 只算四個權限,卻會在 document_start、all_frames、對應 <all_urls> 注入。optional_permissions 更不會出現在安裝提示裡——Table Capture 可以在執行時請求 userScripts,而這會讓它在頁面情境中執行任意使用者腳本;Magical 則可以請求 webRequest。
哪一個要求得最少?
Agenty:四個權限,沒有 host 權限,也沒有內容腳本。它依賴 activeTab,只有在你點擊擴充功能之後、而且只到你離開目前分頁之前,才給予那個分頁存取權。第二少的是 Hexomatic,兩個權限,內容腳本也只限於自己的網域。
擴充功能怎麼不宣告 file:// 也能碰到我的本機檔案?
因為 <all_urls> 包含 file: scheme。Listly、Magical 與 Table Capture 都明確寫了 file:// 模式——Magical 在內容腳本中寫,Table Capture 則是在 web_accessible_resources 中寫。Axiom.ai 與 Thunderbit 則是透過萬用字元碰到它,完全沒有提到。http://*/* 與 https://*/* 不涵蓋 file://。Chrome 把檔案存取預設關閉,放在每個擴充功能自己的切換開關後面,所以這種宣告只是請求,不是直接授權。
什麼是 externally_connectable?為什麼省略它反而比較寬鬆?
它用來指定哪些 web origins 或擴充功能 ID 可以向擴充功能的背景腳本送訊息。Chrome 的預設行為是:當這個鍵不存在時,任何擴充功能都可以連線,但沒有任何網頁可以連線。這十個裡有七個都省略了它,包括 Thunderbit。當這個鍵存在時,Hexomatic 會把擴充功能通道開給八個指定 ID;Axiom.ai 會開放七個 web origins,但擴充功能通道仍然關閉;Magical 則把兩邊都設成空清單,因此兩條通道都關掉。
Thunderbit 自己的 manifest 宣告了什麼?
<all_urls> 用於 host 存取與靜態內容腳本注入,並在 document_end、all_frames 中執行;15.9 MiB、78 個檔案;以及權限陣列中的九個字串。八個是 Chrome 可識別的權限:activeTab、debugger、offscreen、scripting、sidePanel、storage、tabGroups 與 tabs。commands 是頂層 manifest key,放在這個陣列裡不會產生效果。這組裡沒有其他擴充功能宣告 debugger。Thunderbit 也在 Chrome 的檔案存取門檻啟用後,透過 <all_urls> 觸及 file://,並省略了 externally_connectable。本次沒有執行 runtime 行為,所以審核也沒有主張它實際呼叫了哪些 CDP 或 scripting method。


