Stories

Detail Return Return

提升 Web 端 JavaScript 的可信度:WAICT 體系詳解 - Stories Detail

提升 Web 端 JavaScript 的可信度:WAICT 體系詳解

在這裏插入圖片描述

在當前互聯網時代,網頁是最強大的應用平台。只要在瀏覽器中擁有合適的 API,你理論上可以安全運行任何你想運行的東西。不過——除了“加密學”這塊。事實上,自 2011 年以來,“網頁中的 JavaScript 加密”一説就被認為是“不靠譜”的。 其核心問題在於:代碼的分發。如果我們在客户端瀏覽器中生成密鑰,從而讓用户能夠發送/接收端對端加密消息,那麼如果應用被篡改,惡意者究竟有什麼阻止他們修改 JavaScript 代碼並將消息外泄呢?

相比之下,智能手機應用商店在這方面做得比較完善:它們為應用生態提供了完整性保障(確保所交付的應用未被篡改)、一致性保障(確保所有用户獲取的是同一個版本)以及透明性保障(可見的版本記錄)。

如果我們能讓網頁也具備類似屬性——也就是無需集中式應用商店,也能為網頁應用提供“完整性”、“一致性”、“透明性”保障,那麼對於網頁中運行的加密、錢包、投票系統、機密 LLM 等都會大有裨益。

本文將介紹一個名為 Web Application Integrity, Consistency, and Transparency(WAICT)的方案(Cloudflare 參與了其起草),這是一個由瀏覽器廠商、雲服務商、加密通信/應用開發者聯合推動、在 W3C 擁有支持背景的項目。我們將先從問題定義談起,再逐步構建解決方案。

一、定義“網頁應用”

在談安全保障之前,首先必須明確“網頁應用(web application)”是什麼。智能手機上的應用可以看作一個壓縮包(zip);網頁則由相互關聯的資源組成——HTML、JavaScript、WASM、CSS 等,這些資源既可能來自本域,也可能來自外域;而任一資源變化,都可能大幅改變應用行為。

因此,一個連貫的“應用”定義就要求:應用必須對其所加載的資源做出承諾(commit)。也就是説,需要有機制讓瀏覽器知道“這是這個應用應該加載的資源集合”。下面我們先從“完整性(Integrity)”談起。

二、完整性:從 SRI 到 “完整性清單”

2.1 子資源完整性(Subresource Integrity, SRI)

網頁的一個重要機制是 SRI:瀏覽器允許頁面在 <script><link> 等標籤中指定外部資源的哈希。示例如下:

<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.13.7/underscore-min.js"
        integrity="sha512-dvWGkLATSdw5qWb2qozZBRKJ80Omy2YN/aF3wTUVC5+D1eqbA+TjWpPpoj8vorK5xGLMa2ZqIeWCpDZP/+pQGQ==">
</script>

瀏覽器會下載 underscore.js,然後校驗其 SHA-512 哈希是否與 integrity 屬性中的值匹配;匹配則加載,否則拋錯、不執行。

如果頁面中所有外部腳本、樣式等資源都帶有 SRI 屬性,那麼整個頁面就可被其 HTML 定義。這距離我們想要的狀態已經很接近了。但網頁應用通常包含多個頁面,並且頁面之間還可能相互鏈接。換句話説:頁面無法強制其鏈接的“下一個頁面”的哈希

2.2 完整性清單(Integrity Manifest)

為了讓整個站點(域)下的每個資源都受到完整性保障,WAICT 提出了“完整性清單”的機制:站點向客户端提供一個 JSON 配置文件(manifest),其內容包括:

  • 一個“哈希字典(hashes)”,將資源的哈希值映射到其路徑。路徑為空字符串表示“任意路徑下可能的資源”(例如錯誤頁)。示例如下:
"hashes": {
  "81db308d0df59b74d4a9bd25c546f25ec0fdb15a8d6d530c07a89344ae8eeb02": "/assets/js/main.js",
  "fbd1d07879e672fd4557a2fa1bb2e435d88eac072f8903020a18672d5eddfb7c": "/index.html",
  "5e737a67c38189a01f73040b06b4a0393b7ea71c86cf73744914bbb0cf0062eb": "/vendored/main.css",
  "684ad58287ff2d085927cb1544c7d685ace897b6b25d33e46d2ec46a355b1f0e": "",
  "f802517f1b2406e308599ca6f4c02d2ae28bb53ff2a5dbcddb538391cb6ad56a": ""
}
  • 一個“完整性策略(integrity-policy)”,指定哪些類型的數據被強制檢查、如何檢查。例如:
"integrity-policy": "blocked-destinations=(script), checked-destinations=(wasm)"

將二者合起來後,完整的 manifest 結構類似:

"manifest": {
  "version": 1,
  "integrity-policy": ...,
  "hashes": ...
}

有了 SRI + 完整性清單,那麼整個站點及其瀏覽器端所加載的資源集合就由這個清單的哈希唯一決定。也就是説,整個網站的狀態可被一個哈希值所承諾。

三、一致性與透明性:公開、可監控的日誌機制

3.1 透明性的意義

“透明性(Transparency)”指的是:應用的代碼/資源被記錄在一個公開可訪問、只增不刪的日誌中。這樣做有兩方面好處:

  1. 如果用户被服務到惡意的代碼,且其察覺到了,他們可以向外部證明自己運行的是什麼。
  2. 即便用户沒有察覺,外部審計者也可能在歷史日誌中發現惡意代碼。

注意:透明性不能防止惡意代碼的分發,但至少使其可審計。現在,由於我們已把整個站點狀態濃縮為一個哈希,我們就可以讓這個哈希進入一個公開日誌。以下是我們設計時應滿足的重要要求:

  • 不破壞已有站點 — 應可選擇性啓用,不影響現有網站功能。
  • 不增加額外往返(round-trip)網絡請求。
  • 尊重用户隱私:不得要求用户向新第三方識別/認證。
  • 用户無需保存站點特定數據(無狀態客户端)。
  • 無中心化:不能有單點失敗、單點信任。
  • 啓用門檻低:站點運營方可以輕鬆加入日誌。
  • 停用也容易:站點可以退出日誌機制。
  • 停用透明化也要可被察覺:攻擊者不能悄悄退出機制。
  • 監控功能:站點運營方應能監控其透明化狀態。

3.2 哈希鏈(Hash Chain)

日誌通常實現為追加(append-only)結構,支持“包含證明(inclusion proof)”與“一致性證明(consistency proof)”。最簡單的追加結構即哈希鏈:每個新元素的哈希被串聯進鏈中,最終鏈哈希代表整條鏈。

在這裏插入圖片描述

通過哈希鏈即可構建包含證明和一致性證明。

3.3 為網站構建透明機制

每站日誌(Per-Site Log)

首先,為每個參與透明化的站點單獨建立一個日誌(哈希鏈)。該日誌中的條目即該站點在某時刻的完整性清單(manifest)哈希。

在這裏插入圖片描述

但僅有日誌還不夠,因為日誌運營方若為惡意方,仍可隨意“新增/刪除”條目並重新計算哈希鏈。為防止這種情況,我們引入“見證者(witness)”角色:見證者驗證日誌一致性證明,並對新的鏈哈希進行簽名。

客户端(瀏覽器)在用户訪問站點時,會收到:

  1. 該站點當前的 manifest ;
  2. 該 manifest 在站點日誌中的包含證明;
  3. 見證者對日誌鏈哈希的簽名。 瀏覽器驗證簽名、驗證包含證明、再執行完整性檢查。此時用户可較為確知:該 manifest 已被記錄在日誌中,且日誌沒有被篡改/刪除。
透明服務(Transparency Service)

為了維護所有參與透明化的站點記錄,我們使用一個前綴樹(trie)結構,將「域名 → 站點日誌鏈哈希 + 鏈大小 + 資源託管地址」做映射。

在這裏插入圖片描述

站點加入/更新/退出透明體系時,都會在該前綴樹中更新其條目。見證者需驗證該前綴樹更新證明,並對根哈希進行簽名。

當用户訪問站點時,瀏覽器除了驗證站點日誌、還要驗證:站點日誌是否在前綴樹中包含、前綴樹根簽名是否可信。

此外,為滿足“無額外往返請求”這一要求,瀏覽器可預裝一個「透明預加載列表(transparency preload list)」,其中列出已參與透明體系的站點域名。若站點出現在此列表中,則必須提供包含證明或非包含證明(證明其已退出)。

監控、可退出、無單點
  • 監控:前綴樹葉節點新增了 “created” 時間戳;站點運營方僅需監控“創建時間”和“日誌條目數”即可判斷是否被篡改。
  • 退出透明體系:站點提出退出時,葉節點不是直接刪除,而是置為“墓碑(tombstone)”形式,保留創建時間。
  • 無單點:體系設計支持多個透明服務/見證者,“非中心化”以減少信任或失敗依賴。

在這裏插入圖片描述

四、一致性挑戰:樹不一致與時間不一致

4.1 樹不一致(Tree Inconsistency)

如果多個透明服務的前綴樹對某個站點記錄不一致(即鏈哈希不同),就構成“樹不一致”。一種極端解決辦法是讓客户端要求多個服務的包含證明,但這樣增大負擔。

方案是限制透明服務的數量(類似於 Google Chrome 中採用的證書透明度日誌數量約為8條)。

4.2 時間不一致(Temporal Inconsistency)

時間不一致指:用户可能因為地域、cookie 等因素,訪問到較新的或較舊版本的站點。理論上,如果簽名有效期過長(如十年),站點可能一直提供非常舊的版本而用户不察。

雖然最強一致性(所有用户同時看到完全相同版本)難以實現,但我們可以降低版本分叉的規模。比如令見證者簽名根哈希的有效期較短(例如一週),以限制可服務的版本數量。缺點是:站點即便未更新,也需週期性向透明服務請求新的簽名。

五、超越「完整性/一致性/透明性」:其他增強特性

5.1 代碼簽名(Code Signing)

WAICT 本身並不解決“代碼來自何處”的問題(即來源可追溯性)。例如,Alice 自己託管一個開源軟件版本,Bob 如何確定其與官方倉庫一致?

為此,與 WEBCAT(由 Freedom of the Press Foundation)協議整合:允許站點在 manifest 中加入擴展字段 dev-ids,列出已簽名站點資產的開發者身份(例如通過 Sigstore)。瀏覽器插件可讀取該字段,從而建立信任。

5.2 冷卻期(Cooldown)機制

攻擊者若想悄然退出透明體系或更換籤名開發者身份,可藉助短期停頓。在預加載列表中註冊的站點,客户端可要求:“若站點出現該名單中,則必須為透明啓用狀態,或其退出狀態須已達冷卻期(如 24 小時)之後才接受”。這樣攻擊者若突然切換狀態,將被檢測。

六、部署考量

各角色的信任與資源需求如下:

  • 透明服務(Transparency Service):存儲所有透明化站點的元數據。若有 1 億域名、每條256 B數據,則單棵前綴樹約 26 GB(不含中間哈希)。運營方需具備高可用性且多個服務應無關聯宕機。
  • 見證者(Witness):驗證前綴樹更新、簽名根哈希。存儲需求類似,需要高可用性並長期保管簽名私鑰。
  • 資源託管方(Asset Host):存儲實際代碼/資源。信任要求低,因為瀏覽器已通過哈希校驗。但託管方不能篡改內容,僅可能拒絕服務。
  • 客户端(Client,即瀏覽器):執行所有檢查(包含證明、簽名、完整性等),是最需要信任的部分。

Cloudflare 表示願意在該生態中提供透明服務及見證者角色,但會避免“自我見證”以防利益衝突。

支持替代生態系統

對於如 Tor Browser 這樣的匿名環境,可能不能信任現有透明服務。WAICT 支持將前綴樹託管到區塊鏈上,以滿足無中心化、無需傳統域名驗證的環境需求。

七、下一步與總結

目前 WAICT 仍處於標準化的早期階段。下一步重點包括:

  • 擴展 SRI 支持更多數據類型(例如 WASM、圖片)
  • 標準化完整性清單格式
  • 標準化附加特性(如代碼簽名、冷卻機制)

我們鼓勵開發者關注透明規範草案、參與討論、提交 PR 或 Issue(規範開源於 GitHub)

八、小結:為什麼這對你我很重要?

作為前端/全棧/安全工程師,我們往往假設“在瀏覽器中運行的 JavaScript 就是安全的”。但現實中很多安全問題源於 代碼分發的不確定性:代碼可能被替換、被篡改、版本可能混亂。WAICT 所提供的機制——完整性清單 + 透明日誌 + 前綴樹索引 +簽名機制——力圖為網頁應用構建一個類似於「應用商店簽名校驗」的信任層。

如果你在開發例如網頁錢包、端對端加密應用、投票系統、在瀏覽器運行的 LLM 等敏感應用,理解並儘早採用這些機制,將對你提升安全性、合規性、用户信任度都有重大意義。

user avatar dingtongya Avatar geeklab Avatar vleedesigntheory Avatar kuailedehuanggua Avatar guisijun Avatar baqidenangua Avatar biubiu_5deda9568bbf1 Avatar lizh Avatar naiyouweiyongbao Avatar qqcode168 Avatar buxia97 Avatar mall4j Avatar
Favorites 12 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.