1Password 的登入時,主密碼從未被送到 1Password 的伺服器上。

直到不久前,我還不知道這件事。我原本以為既然是密碼管理工具,伺服器理所當然會接收主密碼,然後用它來解開加密的保險庫。但事實並非如此。

伺服器端只會確認「你知道正確的主密碼」這件事,並不會接收密碼本身。保險庫裡有什麼、開啟保險庫的鑰匙是什麼,伺服器一概不知道。即便如此,登入仍然可以通過。

當我知道這個設計後,終於理解了為什麼 UX 能這麼流暢,同時安全性又這麼強。本文會用「兩把秘密鑰匙」與「不露出內容也能證明的驗證」這兩個機制,來拆解其內部原理。

在好用之中感到違和的瞬間

一切的開端,是我對 1Password 好用程度感到的不協調感。

當我在新裝置上登入時,只需要輸入電子郵件地址和主密碼。接著再掃描一張 QR Code,保險庫就會恢復。幾秒鐘就完成了。

可是,如果真的這麼順暢,那就應該要懷疑一下:「會不會其實是伺服器用主密碼解密了保險庫,再把它灌到新裝置上?」如果真是這樣,那只要伺服器一旦被入侵,全世界使用者的保險庫都會成為暴力破解的目標。

即便如此,1Password 並沒有像 2022 年的 LastPass 事件那樣造成大規模災情。明明很方便,為什麼卻這麼強?這股違和感,就是我開始閱讀官方安全白皮書的起點。

LastPass 在 2022 年被攻破時,發生了什麼事

在進入 1Password 之前,先整理作為對照的 LastPass 2022 年事件。

2022 年 8 月,LastPass 的入侵事件被公開。之後的調查顯示,攻擊者在同年 8 到 9 月期間,從備份儲存區搬走了加密的保險庫資料。到了 11 到 12 月,則陸續向客戶公告。由於個別保險庫是用從主密碼導出的金鑰加密,因此金鑰本身並沒有被直接竊走。

然而,保險庫的中繼資料(例如 URL)沒有被加密,而真正最大的問題也正是從這裡開始。攻擊者可以離線嘗試任意主密碼,持續驗證是否能導出正確的金鑰。

保險庫加密通常會使用像 PBKDF2 這樣的金鑰衍生函數。但這只會讓暴力破解「變慢」,並不會讓它「不可能」。如果使用者的主密碼太短,幾張 GPU 幾天內就能破解。從外洩密碼調查的常見結果來看,你大概也能想像,短密碼總是名列前茅。

當保險庫從伺服器被偷走後,許多密碼管理工具最後還能依賴的防線,只剩下「主密碼的熵」。用了弱密碼的保險庫,往往就在這一關被攻破。這種架構在很多產品裡都可能重現。

這正是它和 1Password 分歧的地方。1Password 的設計,讓守護保險庫的鑰匙有一部分是「伺服器根本無從得知的秘密」。那就是 Secret Key。

秘密 1:用 Secret Key 混入 128 bit(2SKD)

1Password 的核心是 Two Secret Key Derivation,簡稱 2SKD。

Account Unlock Key(以下簡稱 AUK)是用來解開保險庫內秘密金鑰與資料保護金鑰的起點。而 2SKD 的作用,就是從兩個彼此獨立的秘密推導出這個 AUK。第一個是你的主密碼,第二個就是 Secret Key。

Secret Key 是一個 128 bit 的隨機值,會在第一次註冊時由 1Password 客戶端產生。伺服器既不會接收這個 Secret Key,也不會生成它。

從熵來看差異

我們來估算一下現實中主密碼的熵。隨機生成的 12 字元英數密碼,大約是 71 bit(log2(62^12))。若是人類還能記得、也能日常使用的範圍,大概落在 40 到 60 bit 之間。

再加上 Secret Key 的 128 bit,推導函數的輸入熵實際上就超過 200 bit。

秘密的構成有效熵GPU 離線暴力破解弱主密碼 בלבד40 bit幾分鐘強主密碼 בלבד71 bit幾十年主密碼 + Secret Key199 bit在現實時間內不可能只要 Secret Key 有「正常地」混入,保險庫就算從伺服器被盜,離線暴力破解也無法成立。攻擊者不知道 Secret Key,於是搜尋空間會大到超出現實計算資源可踏遍的程度。理論上可以解,但等到有答案時,大概人類都不在了。

派生流程概觀

精確的派生分成兩條路。主密碼那一側使用 PBKDF2-HMAC-SHA256 迭代 100,000 次,salt 是電子郵件地址。Secret Key 那一側則使用以 account ID 為 salt 的 HKDF-HMAC-SHA256。兩者的輸出再以 XOR 合成 AUK。白皮書的 §3 與 §8 有完整規格。

這裡只要抓住一點就夠了:伺服器不知道 Secret Key,因此無法從竊取到的資料重建 AUK。

接著,下一個機制(SRP-6a)會讓這個 AUK 或主密碼在驗證時不需要送到伺服器。

秘密 2:用 SRP「不露出鑰匙也能打開給你看」

另一個主角是 SRP(Secure Remote Password protocol)。

一句話來說,SRP 就是「不把秘密送給伺服器,也能證明自己知道這個秘密」的協定。若改用保險庫來比喻,就是:

我想證明自己握有正確的保險庫鑰匙,但不把鑰匙本身給你看。

以日常直覺來說這很奇怪,但在密碼學裡很常見。密碼驗證的本質其實也是這樣。SRP 的特點是,伺服器只需要保存 verifier,而不是保存密碼本身。密碼相當的值,從來不會在網路上流動。

在伺服器保存 verifier 與 salt

第一次註冊時,客戶端會用 2SKD 算出的值來計算 SRP verifier,然後送到伺服器。verifier 是單向函數的輸出,無法從中還原出原本的主密碼或 Secret Key。

伺服器保存的是這個 verifier 與認證用的 salt。此外,還會保存加密過的金鑰束與加密後的項目本體。但這些資料都不包含主密碼或 Secret Key 本身。無法從 verifier 或加密資料直接打開保險庫。

登入時的互動

登入時,客戶端與伺服器會交換亂數,同時彼此證明「自己持有正確的值」。

整個過程中,主密碼、Secret Key,或相當於 AUK 的值都不會出現在網路上。即使中間人攔截所有封包,也無法從中還原出金鑰。

三層防護

SRP-6a 的優點可以整理成這樣:

  1. 抗伺服器竊取:就算只從伺服器偷走 verifier,也無法反推出主密碼
  2. 抗中間人攻擊:即使攔截通訊,也沒有密碼相當值在流動
  3. 抗離線攻擊:從認證過程錄下來的資料,也幾乎無法拿來試密碼

一般的密碼驗證,這三點一項都做不到。像是直接用 POST /login 傳明文 password 的類型。即使有 TLS 加密,伺服器終究還是會收到密碼本身一次。而在 1Password 裡,連那「一次」都沒有。所謂「只送一次而已」這句話,在安全上往往就是致命傷。

SRP 是 1990 年代就已經存在的老協定。ProtonMail、AWS Cognito 等也有採用案例。不過相關解說文章仍然不多,原因是實作難度高,而且很依賴函式庫品質。

2SKD × SRP 為何不會破壞易用性

2SKD 讓保險庫即使從伺服器被盜,也無法成立暴力破解。SRP 則讓你在不把主密碼送上網路的情況下完成驗證。到這裡,開頭那個違和感的答案就出來了。

當你在新裝置上登入 1Password 時,所需要的只有三樣東西:

  1. 電子郵件地址(用來知道要取哪個 verifier)
  2. Secret Key(2SKD 的其中一個秘密)
  3. 主密碼(另一個秘密)

其中 Secret Key 是第一次註冊時隨機產生的 128 bit,並且只保存在你的裝置上。你必須把它複製到新裝置。

這時候,QR Code 就登場了。你可以在既有裝置上顯示包含 Secret Key 的 QR Code,然後讓新裝置用相機掃描。搬移就完成了。比手動輸入更快,而且不會經過網路。

UX 之所以流暢,其實是因為「讓人類不用直接處理 Secret Key,而改由裝置間搬運」這個設計。驗證不把秘密送給伺服器,所以很快;Secret Key 的搬運則靠 QR Code 幾秒就能完成。一旦 Secret Key 進到裝置裡,之後也幾乎不會再要求重新輸入。

即使增加安全性,只要把它藏在「看不見的地方」,UX 也不會壞掉。1Password 的設計就是這個實例。如果我每次都得意識到 QR Code 裡到底裝了什麼,我大概第一天就不用了。

總結

1Password 的兩個機制,分別扮演了以下角色:

  • 2SKD:即使保險庫從伺服器被偷走,對不知道 Secret Key 的攻擊者來說,離線暴力破解也無法成立
  • SRP-6a:在驗證時,從來不會把相當於主密碼的值送到伺服器

伺服器在不知道保險庫內容、保險庫鑰匙,以及開啟保險庫所需秘密的情況下,仍能驗證你的登入。這就是「好用但又強大」的真相。話說得很像在賣弄,但在我真正理解之前,我其實已經默默用了好幾年,什麼都沒想。

自從開始選擇密碼管理工具後,我也開始用這兩個觀點看其他產品:當保險庫被偷走時,是否只剩你的主密碼在當最後防線?在驗證時,密碼本身是否會送到伺服器?這兩件事到底被保障到什麼程度(我也只是看看而已,畢竟換工具的成本太高,現在還沒真的動手)。

大家在日常工具裡,有沒有見過兼顧 UX 與安全性的取捨解法呢?歡迎在留言裡告訴我。

下一個疑問

讀到這裡,大概會浮現一個問題:「如果伺服器和客戶端彼此都不知道對方的主密碼,那團隊成員又是怎麼共享同一個密碼的?」答案是使用公開金鑰密碼學來分發 Vault Key,也就是每位使用者持有的 RSA 金鑰組,以及 Vault Key 的加密分發方式。續篇會再進一步拆解。

參考

「伺服器和自己都不要過度信任」這種前提下重組系統的想法,也同樣適用於 AI 串接協定的安全設計。想更深入了解的話,也可以參考下面這本書。

MCP 安全實務入門


原文出處:https://qiita.com/kenimo49/items/d1151389d17e50ad5564


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝17   💬3   ❤️4
689
🥈
我愛JS
📝2   💬5   ❤️3
137
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登