載入中…
貼上 base32 secret 或 otpauth:// URI,倒數圓環跟著 30 秒週期轉——驗證碼在你的瀏覽器裡算,不會送去任何地方。
檔案不會離開你的瀏覽器 — 全部在本機處理。
載入中…
TOTP 沒有魔法:拿共享的 secret 和目前時間做 HMAC,截短成六位數字,就這樣——RFC 6238 疊在 RFC 4226 的 HOTP 上的標準做法。幫你註冊的伺服器和產生驗證碼的那一端握著同一份 base32 secret,對同一個 30 秒的時間格做同一套運算,所以完全離線也對得上;也因此,裝置時鐘不準是驗證碼對不上的頭號原因。這頁做的就是這套運算,沒有別的,而且直接拿 RFC 附錄公佈的官方測試向量驗過。
先把話講白:TOTP secret 不是密碼。密碼洩漏了可以換,secret 是之後每一組驗證碼的種子,拿到它的人從今以後都能算出有效的驗證碼——把它貼進一個會上傳的網站,等於直接把第二道防線交出去。這頁是靜態檔案,背後沒有伺服器:驗證碼由你分頁裡的 JavaScript 算出來,secret 不會出現在任何網路請求裡,你自己開 devtools 就能驗證。這是讓人安心的那一半。另一半也得講:secret 存在瀏覽器的 localStorage,就是比鎖著的手機上的專用驗證器 App 弱。沒加密的項目,任何碰得到這個瀏覽器設定檔的東西都讀得到——權限開太大的擴充功能、機器上的惡意程式、路過你沒鎖電腦的人。通行碼加密選項就是為了這個風險存在的,也是它值得開的原因。
設了通行碼之後,項目會先用 AES-GCM 加密才寫進 localStorage,金鑰由你的通行碼經 PBKDF2 推導出來——用的是瀏覽器內建的 WebCrypto,不摻第三方加密程式碼。留在磁碟上的是密文,沒有通行碼就是一堆沒意義的 byte,而通行碼本身不會被存在任何地方。反過來說就是這個設計的重點:通行碼忘了,項目就是沒了。沒有救援、沒有重設信、沒有後門——留給你的後門,同時也是留給別人的後門。這是設計,不是 bug。實際損失也不大:拿備用碼登入該服務,重新註冊一次 2FA,就會拿到一份新的 secret。
新增帳號有三條路:直接貼 base32 secret、貼完整的 otpauth:// URI,或掃註冊用的 QR code——QR 不過就是那條 URI 畫成圖,一樣在本機解碼。多個帳號並排各自顯示驗證碼,點一下複製,倒數圓環告訴你這個 30 秒週期走到哪裡。一個值得養成的習慣:圓環快空的時候,多等一兩秒拿下一組,別跟到期賽跑——多數伺服器會容忍前後各一格,但在換碼瞬間送出的驗證碼,正是輸掉這場賽跑的經典方式。位數和演算法都可以調——6 或 8 位、SHA-1、SHA-256、SHA-512——留給少數不走預設值的服務。
不會,而且這句話不用信我的,自己查。開瀏覽器的 devtools 切到 Network 分頁,新增一個帳號:沒有任何請求帶著 secret 出去;頁面載入完之後把網路整個關掉,驗證碼照樣算得出來。這頁是靜態檔案,背後沒有 API,想上傳也沒有地方可以收。這件事在這頁比在其他工具上都嚴重,因為 secret 洩漏一次就是永久淪陷——它不像密碼可以換掉,只能整個帳號重新註冊 2FA。
九成是時鐘。TOTP 把 Unix 時間切成 30 秒一格,兩邊要落在同一格才對得上,所以裝置時鐘慢一分鐘,算出來的驗證碼都『有效』——只是有效在錯的時間點。多數伺服器照 RFC 6238 的建議容忍前後各一格,大約 ±30 秒的誤差,所以半分鐘以內的漂移通常沒感覺,再大就開始被拒。解法是把系統時鐘修好——開網路自動對時——而不是懷疑 secret 抄錯。剩下一成再檢查:secret 抄寫時打錯字(base32 字母表裡沒有 0、1、8、9),或那個服務其實用 8 位數或 SHA-256,而你的項目還停在預設值。
RFC 6238 定義的 TOTP 預設就是 HMAC-SHA-1、六位數、30 秒一格,市面上幾乎所有服務都用這一套。SHA-1 被攻破的是碰撞攻擊,這打不到 HMAC-SHA-1——要在不知道 secret 的情況下算出驗證碼,得先打穿 HMAC 本身,到今天沒人做到。所以這裡的 SHA-1 不是憑證簽章裡那種等級的問題。設定存在的理由是少數服務用 SHA-256、SHA-512 或發 8 位數的驗證碼;如果服務有講(或它的 otpauth:// URI 帶著 algorithm=、digits= 參數),項目就得跟著設,因為演算法對不上不是偶爾錯,是每一組都錯。
不行,它也沒打算取代。這是個順手工具兼除錯工具:坐在電腦前查個驗證碼很方便、部署前驗證一份 secret 算出來的驗證碼跟伺服器期待的一不一致、或拆開一條 otpauth:// URI 看裡面裝什麼,都很好用。但手機上的專用驗證器把 secret 放在硬體層級的安全儲存裡、鎖在裝置的螢幕鎖後面,清瀏覽器資料不會消失,瀏覽器擴充功能也摸不到。放在 localStorage 的 secret——就算加了密——拿不到這些保護。主力 2FA 請放在真正的驗證器裡、做好備份,這頁拿來做瀏覽器工具擅長的事就好。
救不回來,而且這是設計不是疏失:項目是 AES-GCM 密文,金鑰從你的通行碼經 PBKDF2 推導出來,沒有通行碼,這台機器上不存在任何能解開它的東西——沒有救援流程、沒有重設。如果存在救援,那就是一條別人也能走的路。實際處理很快:用手上還能用的驗證器或備用碼登入各服務,重新註冊 2FA 拿一份新 secret。這也是備用碼存在的意義——把它們放在不是這個瀏覽器的地方。
不會。註冊用的 QR code 拆開來就是一條 otpauth:// URI——帳號名稱、發行方、base32 secret,包成一個 URL 而已。鏡頭畫面由你分頁裡的 JavaScript 解碼,URI 也在同一個地方解析,影像和內容都不會出現在網路請求裡——上面那招 devtools 檢查在這裡一樣適用。但 QR 本身要用對待 secret 的態度對待:註冊 QR 的截圖就是 secret 本人,只要該帳號沒重新註冊,它就一直有效。
Need a strong password to go with that second factor? Generate one.
Inspecting a different kind of credential? Decode an X.509 certificate.
Verifying integrity rather than identity? Compute a file's hash instead.