一個保管箱身份,一個同步中樞
閱讀時間 8 分鐘 作者 NT²
保管箱不必進入共用的明文信箱才能同步。它的公開密碼學身份可以指定專屬的邊緣協調器,用來通知 replica,並指向協調器本身無法開啟的加密 frame。
一個保管箱身份,一個同步中樞
選用的雲端同步功能需要一個會合點。
筆記型電腦上傳加密變更後,手機需要有地方得知保管箱已經前進。兩份 replica 離線後重新連線時,需要在一個共同位置比較進度。裝置若已在線上,一則小型通知就能告訴它取得新的加密資料,不必等到下一次輪詢。
常見答案是共用的同步服務,後方連接共用的多租戶資料表。每個帳號都把資料列寫入同一個邏輯信箱,而應用程式碼則在每次查詢加上租戶條件。
NT² 採取更窄的做法:每個啟用雲端功能的保管箱身份,都有一個 Durable Object 作為唯一的 replica 協調中樞。 這個 object 由保管箱的公開密碼學身份,也就是保管箱金鑰 DID 來命名。它協調該身份的授權 replica,保留發布進度所需的少量狀態,並透過可休眠 WebSocket 傳送輕量的變更通知。加密的 replica frame 本身則以不透明物件形式存放在 R2。
這個中樞不是保管箱。它不持有可讀副本、不搜尋機密,也沒有解密 frame 所需的金鑰。它比較像私人車站的看板:可以告知又有一件加密貨件抵達,卻不能拆封,也不知道內容發生了什麼變更。
共用資料表的誘惑
多租戶資料表廣受採用,理由很充分。它們熟悉、可查詢,而且有效率。團隊可以把所有訊息放進同一張資料表,使用 tenant_id、sequence、payload 與 created_at 等資料欄。索引能快速取得下一頁;客服查詢可以統計延遲的資料列;背景 worker 可以掃描資料表並重試失敗的傳遞。
危險之處並不是關聯式資料庫本身不安全,而是隔離變成應用層必須反覆兌現的承諾。
每次讀取都必須包含正確的租戶條件。每次更新都必須驗證擁有權。每個 join 都必須把邊界一路傳遞下去。每支維護 script、每次遷移、每個佇列 consumer、每份管理匯出與每段除錯查詢,都必須記住同一條規則。只要漏掉一次條件,一般程式錯誤就可能變成跨租戶資料揭露。
框架 helper 與資料庫 policy 可以降低這項風險,卻無法消除共用資料平面帶來的組織壓力。當許多客戶的紀錄位於同一個可查詢介面,內部工具自然會圍繞這個介面成長。維運人員想用更廣的搜尋排查事故;產品團隊要求加入彙總欄位;客服工具需要預覽。接著有人提議在加密 payload 旁儲存明文標題,只因為這樣能讓某個畫面更容易實作。
營運人員的「偷看」文化可能就這樣出現,甚至沒有人正式宣布隱私政策有所改變。schema 讓廣泛可見性變得方便,可見性也就逐漸顯得理所當然。
對保管箱而言,這不是正確的文化預設值。敏感資料不該只隔著一個可能被忘記的篩選條件,就落入另一個租戶手中;可讀欄位也不該只因為共用資料表方便,就進入共用信箱。
讓公開身份選擇房間
每個 NT² 保管箱都有一個保管箱金鑰 DID:這是用來驗證雲端請求的公開密碼學身份。這個身份不是密碼,也不會揭露保管箱內容。它為服務提供穩定的公開資料,用來辨識經授權的簽章。
同一個公開身份也能以確定性方式選出保管箱的 Durable Object。某個保管箱金鑰 DID 的請求都會解析到同一個 object;不同身份則會解析到不同 object。結果是一條簡單的隔離規則:
- 一個保管箱身份只有一個協調位址;
- 只有該身份通過認證的請求可以使用它;
- 該保管箱的所有 replica 排序與即時通知都經過這個中樞;
- 不需要由共用協調器多工處理彼此無關保管箱的可讀狀態。
使用公開身份命名 object,不會讓名稱本身成為機密;這也不是目的。授權仍需要密碼學證明,任何外部請求仍需要一般的驗證與濫用防護。這項設計帶來的是確定性路由與清楚的擁有權邊界,不是靠隱匿維持安全。
Durable Object 也自然適合把 replica 可能互相競爭的短暫時刻依序處理。它可以接受通過認證的通知,得知新的加密 frame 已完成儲存,再推進協調狀態,並告訴已連線裝置目前有更新的位置。由於同一個保管箱的請求會集中至同一個邏輯 object,這項協調不需要鎖住所有客戶的全域機制。
同樣重要的是,object 的職責維持狹窄。它不需要本機保管箱的 schema,不需要登入憑證、筆記、文件類型、標籤或附件名稱等資料欄,只需要協調加密 replica 所需的外層事實。
持久協調,不透明儲存
Durable Object 很適合有狀態的協調,但不適合永久累積每一個加密位元組。replica frame 與附件 chunk 的數量可能很多,體積也可能很大;R2 的用途正是持久保存這類物件。
責任分工是刻意設計的:
- 授權裝置先在本機加密保管箱變更。
- 裝置以不透明物件參照上傳不透明 frame。
- 每個保管箱的 Durable Object 記錄或觀察協調所需的進度。
- 中樞通知其他已連線 replica,目前有更新的位置。
- 授權 replica 取得缺少的 frame,再於自己的裝置上解密。
R2 看見的是位元組、物件參照、大小與存取活動。Durable Object 看見的是 replica 進度與連線狀態等協調事實。兩者都不會收到保管箱金鑰或明文項目欄位。
這條邊界也讓失敗行為更容易理解。WebSocket 通知不是變更的持久副本,只是提示接收端檢查是否有新的 frame。如果手機正在休眠、連線中斷或漏掉通知,加密 frame 仍然留在物件儲存中,replica 可以在下次通過認證的同步追上進度。
因此,中樞能改善延遲,卻不會變成脆弱的訊息匯流排,要求每個 event 都必須恰好送達一次。
讓安靜的保管箱使用可休眠 WebSocket
大多數保管箱在大部分時間都很安靜。使用者可能編輯幾筆紀錄、關閉應用程式,接著數小時甚至數天都沒有其他變更。如果每個已連線但閒置的 replica 都必須維持完整的伺服器程序,將會浪費資源。
可休眠 WebSocket 很適合這種模式。裝置可以維持即時的變更通知通道,而平台能在沒有工作時讓 Durable Object 休眠。流量抵達後,object 會恢復、驗證相關情境,再繼續協調。
通知應該刻意保持精簡。它可以指出進度已前進,或某個已知位置之後有新的 frame;不該包含解密後的標題、筆記預覽、登入憑證類別,或任何從內容衍生的便利欄位。
這件事的重要性不只在頻寬。即時系統往往會吸引業務邏輯。一旦即時通道開始承載已解讀的項目操作,協調器就會逐漸成為另一套可讀後端。讓訊號保持與內容無關,NT² 才能維持通知與解讀之間的區分:
- 中樞知道加密狀態有變更;
- 通過授權且已解鎖的裝置知道變更是什麼。
這已足以提供反應靈敏的同步體驗。
取捨:更多邊緣機制,換取更清楚的隔離
每個保管箱身份配置一個 Durable Object,會增加複雜度。路由必須具備確定性;認證必須把請求綁定至用來選擇 object 的同一身份;物件儲存參照、重試行為、replica 游標、連線生命週期與刪除,都需要仔細處理。營運工具也必須能在不依賴明文內容的情況下診斷協調失敗。
共用資料表搭配一組無狀態 worker,乍看可能更簡單,尤其是在早期。每個保管箱的設計選擇投入更多邊緣機制,換取一條更容易陳述與稽核的邊界:身份 A 的協調位於 A 的 object;身份 B 會抵達另一個 object;兩者都不需要可讀的保管箱資料。
這是協調層的隔離,不是神奇的實體分離。這些 object 仍在共用雲端平台上執行,網路中繼資料仍然存在,實作錯誤也仍可能發生。加密與授權依然不可或缺。依身份路由會減少刻意混合無關租戶狀態的地方,卻不能取代安全工程。
還有另一項重要限制:Durable Object 是選用的,因為雲端同步本來就是選用的。
本機保管箱不必聯絡這個中樞,就能建立、解鎖、搜尋與編輯。如果網路無法使用、object 正在休眠,或使用者從未訂閱同步,裝置上的保管箱仍會運作。本機操作不會等待雲端協調器批准。
連線恢復後,已啟用同步的 replica 可以封裝加密變更、完成認證,再從持久進度繼續。雲端把保管箱延伸到多台裝置,卻不會變成批准保管箱存在的權威。
中樞不能做的事
能力界定了架構,拒絕也同樣重要。
Durable Object 無法解密保管箱內容。 它不會收到主密碼、保管箱加密金鑰,也沒有其他由服務提供者保管、可通往明文的捷徑。把協調移入有狀態的邊緣 object,不代表信任也往同一方向移動。
不會有一個共用 Durable Object 保存許多保管箱的明文。 這種 object 只會用另一個產品名稱重建全域信箱。它會集中可讀的租戶資料、鼓勵廣泛內部查詢,並讓一次路由錯誤變成潛在的資料揭露。
通知不會包含機密預覽。 裝置先得知加密 frame 已備妥,再完成認證、取得資料並於本機解讀。中樞不需要附加標題或類別,讓通知顯得更「有幫助」。
離線使用不需要這個 object。 即時通知失效可能延遲同步,但絕不能讓使用者無法開啟已經位於裝置上的保管箱。
這些拒絕會限制客服工具與伺服器端功能。營運人員可以檢查服務健康、連線失敗、物件數量、時間與授權結果,卻不能開啟一筆紀錄,查看文字為什麼顯得異常。這項限制不是尚未完成的管理功能,而是證明協調器還沒有變成明文控制室。
私人的會合點,不是可讀的主要副本
盲目同步仍需要協調。真正有意義的選擇是:協調器要成為全域、可讀的重力中心,還是維持為加密 replica 的狹窄會合點。
NT² 依每個保管箱金鑰 DID 配置這個會合點。一個身份解析至一個 Durable Object;可休眠 WebSocket 以低成本提供變更通知;R2 保留不透明 frame;授權裝置則在本機執行加密、解密、索引與衝突解讀。
這項設計需要投入更多邊緣工程,卻讓預期邊界變得具體:保管箱的雲端中樞可以協調它的 replica,而不必成為保管箱本身。
若想了解雲端身份為何與本機存取分開,請閱讀解鎖本機保管箱,不等於登入雲端。若想了解這個中樞所協調的加密傳輸模型,請接著閱讀在邊緣進行盲目 replica 同步。如果你想要一個在連線之前、期間與之後都持續可用的保管箱,歡迎開啟 NT² Vault。
最後更新 2026-08-12
相關故事
- 在邊緣進行盲目 replica 同步
閱讀時間 8 分鐘
- 為什麼選擇 PWA 本地優先、零伺服器的 Vault
閱讀時間 5 分鐘
- 有時 USB 隨身碟比 email 更適合
閱讀時間 1 分鐘