‹ 指南

SSH 兩步驗證登入 v26.1.6+

有些伺服器在密碼之後還要 6 位驗證碼。密鑰填一次,之後由 Term 替你回答。

需要 Term v26.1.6 或更新版本。

回答驗證碼這件事從 v26.1.4 起就能用了。v26.1.6 改的是不成功的時候:告訴你是哪一種失敗,以及查清楚這件事要花多少次嘗試。

撰寫於 · 更新於

它做甚麼

有些伺服器不接受單獨的密碼:輸完密碼後還會要一個驗證碼,也就是驗證器 App 上那 6 位數字。這在 SSH 裡是另一種認證方式——伺服器一個一個地提問、等你回答——所以只會傳送密碼的用戶端根本登不進去。

把你交給驗證器 App 的那把密鑰同樣交給 Term,它就會自己回答這些提問:先密碼,再即時生成驗證碼。

目標主機可以,它經過的跳板機同樣可以。兩跳是兩次獨立的登入、各有各的憑證,所以啟用了兩步驗證的跳板機會用它自己的密鑰來回答——這正是 v26.1.4 之前連不上的那種情況。

怎麼設定
  1. 開啟主機——在清單裡長按,選「編輯」,展開進階選項。
  2. 填入密鑰。貼上你在伺服器啟用兩步驗證時看到的那串 base32 密鑰,或點 QR code 按鈕,掃描你本來會用驗證器 App 掃的同一個碼。以 otpauth:// 開頭的整條連結也可以直接貼——Term 會從中取出密鑰。
  3. 儲存並連線。其餘照舊:不會彈出任何提問,驗證碼在連線過程中生成並送出。
主機編輯頁裡的兩步驗證密鑰欄位,右側帶掃碼按鈕。
欄位在「進階選項」裡。QR code 按鈕會開啟掃描器,可以直接掃另一塊螢幕上的設定頁。
哪些能用

Term 生成的是標準 TOTP——RFC 6238,6 位數字,每 30 秒一換。所以問題不在於你用哪個 App,而在於你的伺服器拿甚麼來校驗。下表前兩行是為這篇文章在真實伺服器上實測過的,第三行則是標準本身的推論。

伺服器用甚麼校驗驗證碼是否可用
pam_google_authenticator ✓ 已實測 Linux 上最常見的方案,絕大多數「為 SSH 啟用兩步驗證」的教學裝的就是它。
pam_oath (oath-toolkit) ✓ 已實測 oath-toolkit 提供的模組,是另一套獨立實作。密鑰相同,提問的措辭不同。
privacyIDEA · LinOTP · Authelia ✓ 標準 TOTP 任何校驗標準 TOTP 的實作。這裡沒有實測,但對我們而言它們並無特別之處。
Duo — 不可用 Duo Mobile 的一次性密碼是以計數器為基礎的,而常規流程是推播通知。兩者都不是 Term 能生成的 TOTP 驗證碼。
RSA SecurID — 不可用 SecurID 用的是它自己的演算法,不是 RFC 6238。
SMS · email codes — 不可用 驗證碼是透過另一條渠道發給你的,主機條目裡沒有任何東西能生成它。

你本來在用的驗證器 App——Google 驗證器、Authy、1Password、Aegis、FreeOTP——並不需要被「支援」。它們持有的是同一把標準密鑰,把這把密鑰也給 Term,只是多了一個持有者。另一個請留著。裝著 Term 的手機若遺失或被清除,上面的 App 也一起沒了,還能進得去靠的就是第二個持有者。

不成功時
主機編輯頁拒絕了一串含有數字 0 的密鑰。
密鑰是 base32:只有字母 A–Z 與數字 2–7。0、1、8、9 不在其中——而這幾個恰恰是照著螢幕抄時最容易替換掉 O、I、B、g 的字元。現在 Term 會當場指出來,而不是等到登入失敗。

它說驗證碼或密碼被拒絕

這條提示比過去更窄,而且是刻意的。Term 只交出了密碼和驗證碼這兩個答案,所以使用者名稱和密鑰都不在嫌疑之內——而 v26.1.6 之前這裡寫的是「請檢查使用者名稱、密碼或金鑰」,三樣都點了名,還把最不可能的那樣放在最前面。

如果密碼沒錯,剩下的就是密鑰或者時鐘。驗證碼是由當前時間推出來的,本機時間偏差超過一分鐘左右,算出來的碼伺服器就不會接受:症狀和密鑰填錯一樣,原因完全不同。

Term 提示驗證碼或密碼被拒絕,錯誤碼 E_AUTH_CODE
伺服器不接受這個驗證碼。標題點的是 Term 實際交出的那兩個答案,並把你引向密鑰和時鐘,而不是從來就沒被懷疑過的使用者名稱。

本來能用,忽然就不行了

多數伺服器會給驗證碼限流——常見預設是 30 秒內三次——一旦觸發,連正確的碼也會被拒。請等半分鐘再試,而不是立刻重來。

從 v26.1.6 起,點一次要花的嘗試次數比以前少:Term 不再一上來就用伺服器沒提供的方式,也不再在無從回答時硬塞一個答案。如果伺服器還是在登入中途放棄了,你會看到「伺服器在給出結果之前就中斷了登入」,而不是一條把責任推給你密碼的失敗提示。

提問既不是密碼也不是驗證碼

Term 現在讀的是整個提問,而不只是它的最後一行。伺服器可以把能讀的字放在請求的標題或說明裡,只留一個光禿禿的標記當提示——現實中就有這麼一台,問的是 Two-Step Vertification… / Please Input Mfa Code / (AliyunOTP):,連伺服器自己拼錯的字都照原樣。這一種現在認得出來。如果你那台還是認不出,把原話告訴我們,就能讓它被認出來。

它說這台主機需要驗證碼

伺服器要了驗證碼,而這條主機記錄裡沒有密鑰,也就無從回答。Term 會就此停下,不會送出空的或編出來的驗證碼:錯的答案會被計入伺服器的嘗試次數,在會限流的主機上,這正是把登入鎖死的方式。請在進階選項裡補上密鑰。

如果提示說的是密鑰讀不出來,那是密鑰存著但不是合法的 base32——重新貼一次,並留意上面關於 0、1、8、9 的那段。

Term 提示這台主機需要兩步驗證碼、但沒有存密鑰,錯誤碼 E_AUTH_2FA
主機要驗證碼,而它沒存密鑰。什麼都不會送出去——不送空碼,也不瞎猜——所以伺服器的嘗試次數一次都沒花。而編輯主機就在旁邊,密鑰就填在那裡。
密鑰存在哪裡

密鑰和主機條目存在一起,位於 App 自己的資料庫中——靜態加密,放在只有 Term 能讀取的沙箱裡,除了它生成的那 6 位數字之外不會離開裝置。它不是一份可以被拷走的檔案;手機鎖著時也交不出來:那份儲存要等裝置本身解鎖之後才會解密。

所以真正守著它的是裝置鎖——也正是那把已經在守著此主機密碼的鎖,密碼就存在同一個資料庫裡。Term 還可以再問一次:設定裡的應用程式鎖,會要求通過裝置驗證才能開啟 App。

另外,請留著你原本的驗證器 App。不是為了更安全,而是為了找得回來:手機遺失或被清除時,上面的 App 也一起沒了,而同一把密鑰的第二個持有者,就是你還能進得去的原因。