第三方腳本是一種供應鏈風險
第三方腳本是你沒寫過的程式碼,由你無法控制的公司提供,在你的頁面內以你使用者的會話執行——用供應鏈的話說,它是一個可以隨時改變自身程式碼的依賴,無需發布、無需審查、無需通知。2026 年 10 月,據報導,這一抽象風險變成了具體的損失:一個主要交易網站載入的效能監控腳本被替換成了旨在掏空其使用者的腳本。本文梳理被報導的內容、SRI 實際能阻止什麼、為什麼先鎖定版本再做雜湊、自託管何時是更好的答案,以及讓清單保持誠實的簡短審計流程。
據報導,Polymarket 發生了什麼
據報導,2026 年 10 月 29 日,Polymarket 的國際站在使用者報告帳戶資金流失後將交易置於僅取消模式,約一小時後恢復交易。據報導,該公司自己的聲明將事件歸因於一家被攻破的第三方服務商,稱已將此事移交執法部門,並承諾讓受影響使用者得到全額補償。基於該公司 10 月 30 日復盤的報導稱,攻擊中被取走的金額約為 270 萬美元,計入因交易暫停造成的損失的善意賠付後,退款總額為 390 萬美元;報導中引用的獨立鏈上分析追蹤到了相近的數字,約為 270 萬美元,涉及數百個錢包。這些數字無一在此獨立核實——它們是報導的數字,本文也如此對待它們。
據報導,其機制才是可以泛化的部分。報導中引用的研究人員將惡意程式碼與一家網站效能廠商的真實使用者監控(RUM)腳本聯繫起來——一個小檔案,其全部工作就是在訪客瀏覽器中測量頁面載入速度,按客戶從該廠商的 CDN 嵌入。據報導,該檔案被替換成了一個專為目標網站編寫的負載:它在已登入會話內工作,使用頁面中已存在的該網站自身的交易機制,將頭寸和資金轉移到攻擊者控制的目的地。據報導,其中不涉及智能合約漏洞,也不涉及被盜的密碼或私鑰——被替換的腳本在瀏覽器看來就是頁面本身。這一敘述的每個細節是否經得起後續審視,對教訓而言並不重要:攻擊形態——一個廠商檔案、被替換一次、被每個訪客執行——正是這一類事件的標準形態。
第三方腳本是你的程式碼,只是發布流程是別人的
經典 script 標籤裡沒有沙箱。從廠商 CDN 載入的程式碼在你的源內執行,擁有與你自己的包相同的存取權:它能讀取和修改 DOM、在輸入時讀取表單值、用使用者的會話呼叫你的 API,並把找到的東西傳到任何地方。OWASP 的第三方 JavaScript 指南直白地列出了三項風險——失去對用戶端應用變更的控制、在用戶端系統上執行任意程式碼、向第三方洩露敏感資訊——三者都源於這一個事實。你的審查流程、程式碼凍結和變更委員會止於你自己的建置;廠商的檔案可以被廠商編輯、被攻破廠商的攻擊者編輯,或被在網域過期後重新註冊它的人編輯。
這種不對稱正是「我們信任這個廠商」不是一種控制的原因。信任決定你今天接受誰的腳本;它對那個 URL 明天提供什麼什麼都不說,也在內容變化時給你任何信號。有效的控制是那些要麼消除信任(自己提供檔案)、要麼約束信任(用 Content-Security-Policy 限制任何腳本能做什麼、能把資料傳到哪裡)、要麼在每次載入時機械地驗證信任的東西——這正是 SRI 的用途。從清單開始:你無法對不知道自己擁有的腳本套用這三者中的任何一個,而一旦算上行銷標籤、支援元件和監控嵌入,大多數網站擁有的腳本比其所有者預期的要多。
SRI 能阻止什麼——以及不能阻止什麼
子資源完整性是瀏覽器機制,由 W3C 規範、由 MDN 記錄:頁面在標籤的 integrity 屬性中聲明它期望的檔案的加密雜湊,瀏覽器對實際下載的內容做雜湊,任何不匹配都會拒絕執行該檔案。對於跨源檔案,標籤還需要 crossorigin="anonymous",且伺服器必須傳送 CORS 標頭,瀏覽器才被允許做此檢查。套用於固定函式庫時,SRI 把靜默替換變成響亮的失敗:到達的檔案,要麼逐位元組就是你審查過的那個,要麼根本不執行。如果被報導事件中的監控腳本是以這種方式載入的固定檔案,被替換的負載就會檢查失敗,而不是在使用者會話中執行——這一條件句是誠實的表述形式,因為那個特定的嵌入是否可雜湊,關乎一個動態的按客戶檔案,而那正是下面的困難情形。
SRI 不能阻止什麼同樣重要。它對內容本就應當變化的腳本沒有幫助——標籤管理器容器、個人化和同意載入器、按客戶產生的檔案——因為沒有穩定的雜湊可以鎖定。它不評判你雜湊過的那個檔案:一個忠實交付的腳本在設計上仍可以愛窺探、粗糙或惡意,而 SRI 會永遠愉快地驗證它。它不覆蓋由其他腳本在執行時注入的腳本,不保護從你自己基礎設施提供的第一方檔案,也對合法腳本執行後收集的資料無能為力。SRI 是一項機械保證——就是這些確切的位元組,否則什麼都不行——它與 CSP、廠商審查和從一開始就最小化有多少第三方獲得會話級存取並列,而不是取代它們。本站的安全標頭檢查為這一配對中的 CSP 一側評分。
鎖定版本,否則雜湊無從立足
SRI 有一個先決條件,它讓審計失敗的次數比惡意還多:URL 必須永遠返回相同的位元組。在 latest 地址、浮動主版本,或廠商重新產生的按客戶檔案之上鎖定的雜湊,會在廠商第一次發布更新時失效——而被自傷的 SRI 失敗半夜叫醒過一次的團隊,往往會移除該屬性而不是修復地址,讓頁面比未測量時更糟。持久的順序正相反:先把 URL 改成指名確切版本([email protected]、/v2.4.0/),審查那個版本一次,然後對那個確切檔案做雜湊。版本升級於是成為刻意的事件——新 URL、新雜湊、一次提交——而不是你從使用者那裡發現的環境變化。
鎖定有成本,誠實要求點名它:被鎖定的函式庫不再從廠商那裡接收靜默的安全修補,因此鎖定創造了追蹤發布並刻意升級的義務,與任何 vendored 依賴所帶的是同一種義務。這是一種可管理的義務——發布說明和日曆提醒就能覆蓋它——而且它嚴格優於它所取代的替代方案:在替代方案中,更新以廠商的節奏未經審查地到達,故障以你的節奏未經宣布地到達。把這一對當作一項實踐:鎖定讓內容可定址,雜湊讓它可驗證,審計確保兩者都沒有悄悄腐爛——被 CMS 遷移編輯掉的版本字串與缺失的雜湊一樣常見,而且只略難用肉眼察覺。
自託管,以及審計流程
對於最重要的腳本,有一個更直白的選擇:自己提供檔案。自託管把廠商的伺服器、帳戶和網域從你的執行時供應鏈中整個移除,讓你的正常部署管線審查並雜湊該檔案,並在廠商的 CDN 故障時繼續工作。取捨是真實的——你放棄廠商的邊緣快取和自動更新,承擔自己交付其安全修復的義務,而一些廠商的授權或按客戶產生的檔案根本不允許這樣做——因此明智的劃分按關鍵程度:小型固定函式庫在敏感頁面上自託管;留在 CDN 上的鎖定並雜湊;動態標籤既不能鎖定也不能託管的,用發布者限制、變更審查和 CSP 來治理;並當場刪除任何無人能說明理由的腳本。每刪除一個腳本,就是一條你不再擁有的供應鏈。
讓這一切保持為真的流程短到可以真正執行。每季度一次——以及在任何重新設計、CMS 遷移或新廠商之後——對你的關鍵頁面範本執行第三方腳本與 SRI 審計:它列出靜態 HTML 引用的每個腳本、哪些是第三方、哪些缺少完整性、哪些未鎖定,並為它能擷取到的前若干缺失雜湊計算可直接貼上的 sha384。按影響順序修復——會話、付款和個人資料頁面優先——然後用 SSL 評分器和安全標頭檢查查看傳輸層和標頭層,最後在標籤管理器中收尾,那裡由執行時注入的腳本是靜態審計看不到的:以看待部署日誌的同樣懷疑審查其發布者列表和變更歷史。每季度十五分鐘,對抗一個據報導在上述案例中約一小時就造成數百萬損失的事件類別。