為什麼選擇 PWA 本地優先、零伺服器的 Vault
閱讀時間 5 分鐘 作者 NT²
在雲端優先應用當道的時代,我們往往忽略了一個強大的替代方案:漸進式網頁應用(PWA)。當現代瀏覽器已經能在使用者裝置上完整執行高效、安全、高效能的應用時,為什麼還要維運一套沉重、昂貴且可能成為攻擊面的伺服器基礎設施?
為什麼選擇 PWA 本地優先、零伺服器的 Vault?
現代網頁應用的典範嚴重偏向「雲端優先」模型。我們習慣於需要持續連線、仰賴龐大伺服器端資料庫、並在遠端資料中心執行複雜運算的應用。雖然這套模型帶來便利與無縫同步,卻也引入了三個關鍵挑戰:
- 「蜜罐(Honey Pot)」風險:集中式伺服器儲存大量敏感使用者資料,成為攻擊者眼中的高價值目標。一次資料外洩就可能暴露數百萬使用者最私密的資訊。
- 營運複雜度:維運一套全球可用、高可用性且安全的伺服器基礎設施,既昂貴又耗費人力。它需要大規模擴展、複雜的資料庫管理,以及持續的安全稽核。
- 連線依賴:使用者一失去網路,應用就無法使用。在行動連網與旅行的日常中,「離線模式」往往只是次要、降級的體驗,而非主要狀態。
在 NT²,我們採取了不同的做法。我們打造了一個以**本地優先(local-first)與零知識(zero-knowledge)**為設計核心的結構化數位資產保管庫。本文將深入探討這套讓漸進式網頁應用(PWA)得以作為高效能、安全且完全本地運作之應用的技術架構。
架構:本地優先典範
我們架構的核心哲學很簡單:使用者的裝置才是唯一的真相來源(source of truth)。
將繁重的工作——儲存、索引與加密——從伺服器轉移到客戶端之後,我們為核心使用者體驗實現了「零伺服器」模型。伺服器被降級為可選的、對資料「視而不見」的同步中繼層,而非資料的權威擁有者。
graph TD
subgraph Browser_System [Browser Primary System]
UI[SvelteKit UI]
WASM[wa-sqlite WASM]
OPFS_Storage[(OPFS Storage)]
Mem[In-memory CryptoKey]
UI --> WASM
WASM --> OPFS_Storage
UI --> Mem
end
subgraph Edge_Relay [Cloudflare Edge Optional Relay]
W[Workers]
D1[(D1 Metadata)]
R2[(R2 Blob Storage)]
W --> D1
W --> R2
end
UI -.->|Optional Replica Batch Sync| W
W -.->|Blind Relay| R2
技術深潛
1. 高效能關聯式儲存:超越 IndexedDB
傳統瀏覽器儲存如 IndexedDB 適合簡單的鍵值對,但在處理複雜關聯資料與大規模查詢時會顯得吃力。對於存放數千筆結構化資產的保管庫,我們需要 SQL 的威力。
我們實作了 wa-sqlite——SQLite 的 WebAssembly 移植版本,將完整的關聯式資料庫能力直接帶進瀏覽器。然而,標準的 WASM 版 SQLite 常因與瀏覽器儲存互動的方式而遭遇效能瓶頸。
為解決這個問題,我們運用了 OPFS(Origin Private File System,源站私有檔案系統)。
OPFS 提供專為網頁應用設計的高效能、低延遲檔案系統。透過 OPFSCoopSyncVFS(Cooperative Sync Virtual File System,協作式同步虛擬檔案系統),wa-sqlite 能在使用者本機磁碟上執行直接、高速的 I/O 操作。這讓保管庫得以處理大型資料集與複雜的 FTS5(Full-Text Search,全文搜尋) 查詢,效能可與原生桌面應用相媲美。
2. 加密基礎:零知識安全性
安全性不是事後補強,而是地基。我們的「零知識」保證意味著:即便我們的伺服器遭到入侵,攻擊者也只會看到一堆毫無意義的密文。
我們使用現代瀏覽器原生提供的高效能加密介面 Web Crypto API 來實現這一點。我們的實作遵循嚴格的階層:
金鑰派生(Key Derivation)
當使用者建立保管庫時,我們不只是儲存一組密碼。我們使用 PBKDF2(Password-Based Key Derivation Function 2,基於密碼的金鑰派生函式 2),以 SHA-256 進行 100,000 次迭代,將使用者的主密碼延伸為高熵的主金鑰。這個過程在設計上刻意耗費運算資源,使暴力破解攻擊難度大幅提升。
緩解 XSS:不可抽取(Non-Extractable)的安全保證
我們實作最關鍵的安全特性之一,就是使用不可抽取的金鑰。
在典型的網頁應用中,若惡意腳本(XSS)在使用者 session 中成功執行,往往能存取敏感資料、甚至是用來加密的金鑰。我們的緩解方式,是在透過 crypto.subtle.deriveKey 派生保管庫的 AES-GCM 加密金鑰時,將 extractable 參數設為 false。
// 概念性實作
const vaultKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: 100000,
hash: "SHA-256"
},
passwordKey,
{ name: "AES-GCM", length: 256 },
false, // <--- 關鍵:金鑰無法從瀏覽器匯出
["encrypt", "decrypt"]
);
將 extractable: false 設為不可抽取後,產生的 CryptoKey 物件只存在於瀏覽器記憶體中。即便惡意腳本成功執行,也無法透過呼叫 exportKey() 來「竊取」金鑰。這把金鑰在 JavaScript 環境中物理上無法匯出,提供了一道強大的縱深防禦層。
已驗證加密(Authenticated Encryption)
每一筆敏感資料都使用 AES-GCM(Advanced Encryption Standard with Galois/Counter Mode,搭配伽羅瓦/計數器模式的進階加密標準)加密。AES-GCM 透過驗證標籤同時提供機密性(隱藏資料)與完整性(確保資料未被竄改)。我們為每一次加密操作產生全域唯一、隨機的初始化向量(IV),確保同一筆資料加密兩次會得到不同的密文。
sequenceDiagram
participant User
participant Browser
participant Storage
User->>Browser: 輸入主密碼
Browser->>Browser: PBKDF2
Browser->>Browser: deriveKey
Note over Browser: Vault Key 暫存於記憶體
User->>Browser: 儲存敏感項目
Browser->>Browser: AES-GCM
Browser->>Storage: 儲存密文與 IV
3. PWA 的優勢:效能與韌性
透過 SvelteKit 建構我們的 PWA,我們得以將網頁應用視為任意裝置上的一等公民。
- Service Workers:我們使用 Service Worker 快取應用程式殼層與靜態資源,讓保管庫即使離線也能瞬間載入。
- 離線優先體驗:由於整個資料庫與加密邏輯都位於本地,使用者體驗流暢無縫。在等待伺服器回應搜尋查詢或解鎖保管庫時,沒有「載入中」的轉圈圈。
- 原生級效能:SvelteKit 高效的響應式更新,搭配
wa-sqlite+OPFS的高速 I/O,帶來反應靈敏、俐落如原生桌面或行動應用的介面。
零知識保證:為什麼重要
「零伺服器」模型不只是為了降低成本,更在於從根本上改變信任模型。在傳統雲端優先的應用中,你信任供應商會:
- 安全地儲存你的資料。
- 不去存取你的資料。
- 不遺失你的資料。
在 NT² 的架構中,伺服器是**視而不見(blind)**的。它只看到加密後的 blob 與非敏感的中繼資料。它看不見你的項目、你的附件,甚至看不見你的身份(身份由密碼學的 Key DID 管理)。這徹底消除了「蜜罐」風險——沒有可供竊取的明文密鑰中央資料庫。
安全設計要點(NT² Vault)
- 主密碼永不離開客戶端:所有金鑰派生、加解密都在瀏覽器中完成,且
CryptoKey設為不可抽取(extractable: false)。 - 自動鎖定機制:5 分鐘無操作或頁面關閉時,立即清除記憶體中的金鑰與解密資料。
- 鹽值本地儲存:每個保管庫在
vault_meta中保存唯一的 salt 與驗證碼,絕不向 Workers 請求或上傳。 - 附件加密分離:附件以二進位形式加密後存於 OPFS 或 Tauri 本機檔案系統,僅在需要時透過 BlobStore 讀取。
結語
「沉重伺服器」模型,是針對一個對隱私導向應用而言本不該存在的問題所提出的解法。透過擁抱現代瀏覽器的力量——WASM、OPFS 與 Web Crypto API——我們已經證明:建立一個高效能、功能豐富且極為安全的保管庫,完全不需要對中央伺服器付出任何信任。
NT² 基於這項原則建立:你應該擁有自己的資料,也應該擁有開啟它的金鑰。 藉由將複雜度推向邊緣(使用者的裝置),我們打造出一個比傳統以雲端為中心之替代方案更安全、更具韌性,也更易於擴展的系統。
你可以在 nt2.me/zh-TW/about 閱讀 NT² 的隱私姿態,或透過 RSS 追蹤新文章。
最後更新 2026-07-13
相關故事
- 不是另一個密碼管理器登入項目
閱讀時間 2 分鐘
- 媽媽把密碼寫在紙本筆記本裡
閱讀時間 2 分鐘
- 桌面上的那份試算表
閱讀時間 2 分鐘