跳至主要內容

KDF 鹽值留在你的裝置上

閱讀時間 8 分鐘 作者 NT²

鹽值不是祕密,但它存放的位置,決定了誰能組成一套密碼猜測系統。NT² 將 KDF 鹽值與密碼驗證資料留在本機保管箱內,讓解鎖從頭到尾都在裝置上完成。

KDF 鹽值留在你的裝置上

主張:解鎖材料應該與保管箱放在一起

NT² Vault 不會要求伺服器許可,才讓你解鎖本機資料。

密碼式金鑰派生路徑所需的材料,都保存在本機保管箱設定檔:每個保管箱獨有的鹽值、 PBKDF2 參數,以及密碼驗證資料。主密碼在你的裝置上輸入,Web Crypto 也在同一台 裝置上執行派生,產生的金鑰材料只在本機使用。整個解鎖流程不需要把密碼、密碼的 衍生值或鹽值送往邊緣服務。

這條界線說來簡單,實作時卻很容易逐步鬆動。一項產品可以在上傳前加密每筆資料, 同時仍讓伺服器成為解鎖的必要環節:把鹽值存在帳號資料庫、提供鹽值查詢端點,或將 可驗證密碼的還原材料與加密副本放在一起。內容或許仍是密文,但服務供應者已經湊齊 測試密碼猜測所需的材料。

我們選擇更明確的界線:雲端不參與本機解鎖協定。

這不表示鹽值本身必須保密。密碼學上的鹽值通常就以明文保存。它的用途,是讓不同 保管箱即使使用相同密碼,也會派生出不同金鑰,並阻止攻擊者用同一份預先計算表攻擊 大量使用者。真正重要的問題不是「攻擊者是否可能知道某一個鹽值」,而是「攻陷一個 中央服務後,是否能一次取得大量鹽值,以及足以驗證密碼猜測的其他材料」。

NT² 選擇不建立這份集中清冊。

限制:雲端還原可能變成密碼神諭

密碼式加密有一項無法迴避的特性:只要攻擊者取得正確輸入與可靠的成功訊號,就能 離線測試猜測。他不必持續連回真正的應用程式,因此速率限制、警示、IP 封鎖與帳號 鎖定全都失去作用。整個迴圈可以在攻擊者控制的硬體上執行:

  1. 取一組候選密碼。
  2. 用該保管箱的鹽值執行指定的 KDF。
  3. 嘗試驗證已知密文或驗證資料。
  4. 若驗證成功,就保留這組候選密碼。

PBKDF2 會提高每次嘗試的成本。NT² 的密碼式派生路徑使用 PBKDF2、SHA-256 與 100,000 次迭代。這個成本很重要:它拖慢每一次猜測,也避免直接拿原始密碼當作 加密金鑰。每個保管箱都有獨立的 16 位元組隨機鹽值,因此攻擊者無法把一份預先 計算結果攤用到所有保管箱。

但 PBKDF2 不會把弱密碼變成強密碼;一旦輸入材料已被複製,它也無法恢復線上服務 原有的速率限制。攻擊者可以在本機驗證猜測後,防守方的伺服器便不再位於迴圈之中。

因此,「鹽值反正是公開的」只說對了一半。目標不是讓鹽值成為祕密,而是避免集中 保存可供密碼驗證的完整材料組合。鹽值本身不是驗證器;缺少派生輸入時,驗證資料 也不該單獨發揮作用。然而,一套還原服務往往會想收集兩者,再加上包裝後的金鑰或 密文,因為它若要承諾便利的還原,恰好就需要這些東西。

這就是「客服總能救回帳號」的幻想:客服一方面要保證能讓你重新進入保管箱,另一 方面又聲稱在密碼學上絕對無法協助任何其他人進入。當還原仰賴伺服器保存的密碼材料 時,兩個目標彼此衝突。如果服務能識別你的保管箱、提供 KDF 輸入,並判斷密碼派生 金鑰是否正確,那麼這項服務——或複製其資料庫的攻擊者——就擁有一個密碼神諭。

把資料庫稱為「託管」並不會改變它的安全性質。

最安全的中央密碼資料庫,就是不建立它。選用的雲端功能可以中繼加密副本、協調 同步,也可以把帳號綁定至公開的密碼學身分;它們不需要參與密碼派生。

設計:本機鹽值、本機驗證資料、密碼學雲端身分

建立保管箱時,裝置會使用 crypto.getRandomValues() 產生全新的隨機鹽值。鹽值 與解鎖該保管箱所需的中繼資料一起存進本機保管箱設定檔,雲端註冊時不會上傳。

瀏覽器先把主密碼匯入為 PBKDF2 的輸入材料,再要求 Web Crypto 以 PBKDF2-SHA-256 和 100,000 次迭代派生 256 位元金鑰。對目前建立的保管箱而言, 這把密碼派生金鑰扮演金鑰加密金鑰,用來開啟受密碼保護的解鎖因子;實際運作的 保管箱金鑰則由裝置在本機組合必要因子後重建。較舊的保管箱格式可能更直接地使用 密碼派生的 AES 金鑰。兩種情況的 KDF 邊界都相同:密碼、鹽值、派生材料與解鎖 嘗試全都留在裝置上。

實際使用的 AES-GCM CryptoKey 會設定為不可抽取。JavaScript 可以要求 Web Crypto 使用這把金鑰執行獲准的操作,卻無法透過 exportKey() 取回原始位元組。 不可抽取並不代表遭入侵的網頁就完全無害——在保管箱已解鎖時執行的惡意程式碼, 仍可能要求金鑰執行操作或讀取畫面上的明文——但它移除了直接匯出金鑰的簡單路徑, 也縮小了可被偷走、留待日後使用的材料範圍。

為什麼仍需要密碼驗證資料?

AES-GCM 提供已驗證加密。解密時,驗證標籤不是成功通過,就是失敗。NT² 利用這個 性質建立一小段本機密碼驗證資料:以密碼派生金鑰和全新的初始化向量加密已知明文, 再把所得密文保存在本機保管箱儲存空間。

解鎖時,裝置先派生候選金鑰,再嘗試驗證這段密文。成功代表密碼派生金鑰正確; 失敗則可明確回報「密碼錯誤或資料損壞」,而不是讓應用程式拿著錯誤金鑰繼續執行, 最後才以難以理解的方式失敗。

這份驗證資料不是密碼雜湊、不是主密碼副本,也不是傳給客服的安全問題答案。它是 刻意設計成可供密碼驗證的密文。也正因如此,它不該與所有使用者的 KDF 鹽值一起 放進中央帳號資料表。

每次 AES-GCM 加密還需要在同一把金鑰下使用唯一的 IV。驗證資料有自己的隨機 IV, 其他加密操作也一樣。在同一把 AES-GCM 金鑰下重複使用 IV,可能同時破壞機密性與 完整性;採取本機設計並不會放寬這條規則。

邊緣服務改為接收什麼?

雲端註冊把保管箱綁定至密碼學身分。裝置只傳送挑戰—回應驗證所需的公開材料。之後 若要證明控制權,已解鎖的客戶端會用私密簽章金鑰簽署新的隨機挑戰;邊緣服務再使用 已註冊的公開金鑰驗證簽章。

這個身分不是電子郵件地址,也不是從主密碼派生而來。更換密碼不必連帶更改雲端 帳號。即使為了收據而提供帳務電子郵件,它也不是解鎖識別碼。最重要的是,雲端註冊 不需要 KDF 鹽值、密碼驗證資料、受密碼保護的解鎖因子,或明文私密金鑰。

這項分工是刻意的:

  • 本機設定檔儲存空間保存鹽值與可供密碼驗證的密文。
  • 裝置記憶體只在保管箱解鎖期間保存已解開的金鑰。
  • 邊緣服務保存公開身分材料與選用的加密副本資料。

因此,本機解鎖可以完全離線運作。網路中斷不會妨礙瀏覽器開啟已存在於裝置上的 保管箱。即使邊緣服務的帳號資料庫遭到入侵,攻擊者也無法取得伺服器端密碼重設流程 的另一半,因為這套流程根本不存在。

若要把保管箱搬到另一台裝置,使用者必須透過自己掌控的明確路徑移動必要的本機 材料。加密備份可以攜帶可移植的保管箱設定檔;裝置連結流程也能傳送新副本所需的 內容。雲端不會只憑一個電子郵件地址,悄悄重建解鎖狀態。

取捨:你遺失的材料,我們無法代為補回

這項設計移除了一項許多人對線上產品習以為常的能力:如果你遺失唯一保存保管箱的 裝置,同時也遺失所有可用備份或還原因子,NT² 無法恢復你的存取權。

沒有一份隱藏鹽值留在營運資料庫等待客服取用,沒有客服專用的主金鑰,也沒有能把 帳務紀錄轉成解鎖權杖的管理員指令。客服可以說明備份與還原選項,卻無法憑空製造 從未傳給我們的密碼學材料。

結果相當嚴峻,因此產品必須讓「擁有資料」成為可實行的日常,而不只是口號。備份 必須可以匯出,還原材料必須清楚呈現,裝置移轉也不能仰賴使用者記住某個隱晦的雲端 帳號程序。關於遺失最後一份副本的警告,必須直接明確,不能藏在設定頁深處。

這不是抽象的「安全性與易用性」二選一,而是一筆具體交換:

  • 你失去由服務供應者操作的密碼重設。
  • 服務供應者失去集中式密碼猜測介面,也失去解鎖你保管箱的能力。
  • 你得到一個可離線使用的保管箱,但能否持續存取,取決於你所控制的副本。

這份責任不會適合每一個人。假裝所有人都適合,反而是不負責任的安全溝通。NT² 適合想要真正託管界線、也願意維護還原路徑的人。

我們拒絕什麼

我們不會加入用「忘記密碼」電子郵件重設主密碼的功能。電子郵件可以證明你能存取 某個收件匣,卻無法重建只在裝置上派生與使用的金鑰。若讓電子郵件足以解鎖,就必須 建立第二個解鎖權威,並因此改變每一個保管箱的威脅模型。

我們不會加入在解鎖期間回傳 KDF 鹽值的伺服器端點。本機解鎖只讀取本機保管箱 設定檔。新裝置必須透過使用者控制的備份、還原或交接路徑加入,而不是向邊緣服務 索取密碼派生材料。

我們不會因為內容資料庫裡只有密文,就把伺服器保存的密碼材料稱為「零知識」。 零知識是整個系統的性質,涵蓋註冊、還原、同步、客服工具,以及資料外洩後的失敗 模式。

我們也不會承諾客服能還原那些我們從設計上就無法讀取的資料。這種承諾若非虛假, 就是系統存在後門的證據。

結語:不方便本身也是證據

本機 KDF 鹽值看似只是小小的實作細節,卻帶來一項重要結果:邊緣服務無法成為解鎖 的必要參與者。搭配本機驗證資料、裝置端 Web Crypto 與密碼學雲端身分,密碼邊界 得以留在保管箱所在的位置。

這是 Null Trust² 真正含義的一項具體實踐: 降低信任的方法,是移除服務供應者的能力,而不是寫下更有力的保證。它也使可攜式 備份成為資料所有權不可或缺的一部分——逃生門是你自己持有的檔案,而不是我們假裝 提供的密碼重設。

如果這種託管模式符合你對保管箱的期待,可以開啟 NT² Vault,把解鎖邊界留在自己的裝置上。

最後更新 2026-07-23

相關故事