修正 SSH Too many authentication failures 錯誤
SSH agent 提供過多金鑰會觸發「Too many authentication failures」。使用 ssh -v 找出問題,並限制每次連線只提供正確金鑰,避免超過預設 6 次失敗。
「Too many authentication failures」的含義
「Too many authentication failures」表示 SSH 用戶端提供給伺服器的金鑰數量超過伺服器願意檢查的上限。伺服器在嘗試正確金鑰之前就關閉了連線。這幾乎總是用戶端問題。金鑰雖然位於磁碟上,伺服器也已將其放在 authorized_keys 中,但這兩點都沒有幫助,因為連線過早結束。
流程如下。ssh-agent 會保存你載入其中的所有私密金鑰。用戶端會逐一將這些金鑰提供給伺服器,因為它無法預先知道該帳戶接受哪一把金鑰。伺服器會拒絕不在 authorized_keys 中的金鑰,並將每次拒絕都計為一次驗證失敗。MaxAuthTries 中的 sshd_config 會限制單一連線允許的失敗次數。預設值為 6。如果你的 agent 中載入了 10 把金鑰,而正確的金鑰排在第 8 個,伺服器會在嘗試到它之前中斷連線。
因此,修正方式是讓用戶端只提供一把金鑰:正確的那一把。
伺服器計算的項目,以及 MaxAuthTries 的作用
公開金鑰驗證一開始像是在猜答案。用戶端送出公開金鑰,詢問伺服器是否接受使用該金鑰產生的簽章。伺服器會回答接受或拒絕。「拒絕」就是一次失敗嘗試,與輸入錯誤密碼完全相同。
sshd_config(5) 手冊頁說明了這項限制:「指定每個連線允許的驗證嘗試次數上限。失敗次數達到此值的一半後,後續失敗會寫入日誌。預設值為 6。」
對於手動輸入密碼的人來說,6 次嘗試已經足夠。但對持有 10 把金鑰的 agent 來說,這並不多。失敗次數超過上限後,sshd 會中斷連線,並在系統日誌寫入類似以下的內容:
error: maximum authentication attempts exceeded for deploy from 203.0.113.10 port 51292 ssh2用戶端會顯示同一事件的另一部分:
Received disconnect from 203.0.113.10 port 22:2: Too many authentication failures
Disconnected from 203.0.113.10 port 22這與 SSH permission denied (publickey) 錯誤 不同。後者表示伺服器已檢查你提供的所有項目,但沒有接受任何一項。此處則表示伺服器停止檢查。將兩者視為同一種錯誤,往往會讓人花上一個下午重新複製其實已經正確的金鑰。
為什麼相同的金鑰在同事的筆電上可以使用
金鑰本身和伺服器都沒有不同。對方的 agent 中有 2 把金鑰,而你的 agent 中有 12 把。對方先送出的金鑰在你的排序中排到第 9 個,此時連線已經結束。
金鑰數量會在不知不覺中增加。AddKeysToAgent yes 在 ~/.ssh/config 中每次使用金鑰時,都會將該金鑰加入 agent 並保留在其中。Linux 上的 GNOME Keyring 或 macOS 的 login keychain 等桌面金鑰圈 agent,會在登入時自動載入金鑰,不會先詢問。經過 1 年,加入用戶端金鑰、git 主機金鑰和實驗室主機金鑰後,某天原本一直正常運作的伺服器開始拒絕你的連線。伺服器沒有任何變更。只是你的 agent 中累積了更多金鑰。
如何使用 ssh -v 查看提供的金鑰
使用 -v 執行失敗的連線,並查看追蹤資訊。
ssh -v deploy@203.0.113.10有兩種日誌行需要注意。Will attempt key: 會列出用戶端整理出的身分,順序就是實際使用的順序。Offering public key: 則會針對實際傳送給伺服器的每個金鑰各出現一次。
debug1: Will attempt key: /home/you/.ssh/id_ed25519 ED25519 SHA256:AAAA... agent
debug1: Will attempt key: /home/you/.ssh/id_rsa RSA SHA256:BBBB... agent
debug1: Offering public key: /home/you/.ssh/id_ed25519 ED25519 SHA256:AAAA... agent
debug1: Authentications that can continue: publickey,password
debug1: Offering public key: /home/you/.ssh/id_rsa RSA SHA256:BBBB... agent實際使用的路徑、金鑰類型和指紋會有所不同。要計算的是中斷前出現的 Offering public key: 行數。如果提供的金鑰持續增加,而工作階段在預期的金鑰出現前結束,就可以確定診斷結果。行尾的 agent 表示該身分來自 ssh-agent。explicit 則表示它來自 IdentityFile 行,或來自命令列上的 -i。
接著查詢 agent 目前載入的內容:
ssh-add -l輸出的每一行代表一個已載入的金鑰。如果輸出 The agent has no identities.,表示問題不在 agent,應改為查看 ~/.ssh/config 中的 IdentityFile 行。如果輸出 Could not open a connection to your authentication agent.,表示目前沒有執行中的 agent,提供的金鑰來自預設金鑰檔案。
修正方法 1:每個主機使用一個金鑰並設定 IdentitiesOnly
IdentitiesOnly yes 會要求 ssh 只提供你設定的身分,並忽略 agent 主動提供的其他身分。搭配 IdentityFile 行使用後,client 只會送出一個身分。
Host vps
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519_vps
IdentitiesOnly yes將設定儲存至 ~/.ssh/config,然後執行 chmod 600 ~/.ssh/config。如果檔案可由群組或所有使用者寫入,ssh 會拒絕執行,並顯示 Bad owner or permissions on /home/you/.ssh/config。現在 ssh vps 只會提供一個金鑰,而 ssh -v vps 應該只會顯示一個 Offering public key: 行。
這裡有兩個容易令人誤解的細節。
IdentitiesOnly yes單獨使用不代表「一個金鑰」。預設身分檔案也會列入已設定的身分,因此 ssh 仍會嘗試~/.ssh/id_ed25519、~/.ssh/id_rsa及找到的其他預設檔案。你還需要IdentityFile行。- 簽署仍由 agent 執行。
IdentitiesOnly控制要提供哪些金鑰,不是控制由誰進行簽署。如果IdentityFile指定的私密金鑰已載入 agent,agent 會產生簽章,你不會被要求輸入 passphrase。你甚至可以讓IdentityFile指向相符的.pub檔案;當私密金鑰只存在於 agent 或硬體 token 時,就應採用這種設定。
~/.ssh/config 中有一個陷阱會悄悄抵銷這項修正。大多數關鍵字會採用找到的第一個值,因此特定的 Host 區塊應放在 Host * 之前。IdentityFile 不遵循這項規則。手冊說明:「設定檔中可以指定多個身分檔案;所有這些身分都會依序嘗試。」在 Host * 下方的 IdentityFile 會附加到每個主機的設定,而不是取代該設定,因此遺漏的全域行會讓額外的身分重新出現在每個連線中。
如果你想設定全域安全防護,只在檔案底部設定這個旗標:
Host *
IdentitiesOnly yes之後每個主機都需要自己的 IdentityFile,這正是你希望達成的結果。為每台伺服器指定一個金鑰,也能讓你日後只撤銷單一機器的存取權,而不必重新簽發所有金鑰。這項習慣值得及早建立:請參閱 如何管理每台機器的 SSH 金鑰。
修正 2:清除或重新啟動 agent
如果目前還不能編輯設定,請先清空 agent,只載入需要的內容。
ssh-add -l # list what is loaded
ssh-add -d ~/.ssh/id_rsa # remove one key
ssh-add -D # remove every key
ssh-add ~/.ssh/id_ed25519_vps # load the one you need如果執行 ssh-add -D 後連線立即恢復,表示問題出在 agent。請將這視為測試,而不是修復。桌面 keyring agent 會在下次登入時重新載入金鑰,因此問題明天會再次出現。~/.ssh/config 中的 IdentitiesOnly 設定行會在重新開機後保留。清空的 agent 則不會。
您也可以為金鑰設定存留時間,讓 agent 自動清除:
ssh-add -t 1800 ~/.ssh/id_ed25519_vps金鑰加入 1800 秒後會被移除。重新啟動 agent 也可解決問題,但具體方式取決於啟動 agent 的來源。若是自行啟動的 ssh-agent,請使用 ssh-agent -k 停止。若是透過自行建立的 systemd user unit 執行,請使用 systemctl --user restart <unit> 重新啟動該 unit。keyring agent 會隨桌面工作階段重新啟動。
修正 3:只使用一次之伺服器的一次性指令
對於不會加入設定檔的主機,請直接在命令列指定相同設定:
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps deploy@203.0.113.10單獨使用 -i 是最常見的錯誤修正方式。-i 會將金鑰加入身分清單,但不會從清單中移除 agent 的金鑰。因此,其他金鑰仍會先於你的金鑰送出,連線仍會在達到限制時中斷。若不使用 IdentitiesOnly 執行 ssh -v -i ~/.ssh/id_ed25519_vps deploy@203.0.113.10,你會看到 agent 的金鑰先被送出。-i 必須搭配 -o IdentitiesOnly=yes 使用。
若要在單次連線中完全停用 agent:
ssh -o IdentityAgent=none -i ~/.ssh/id_ed25519_vps deploy@203.0.113.10接著,ssh 會直接從磁碟讀取私密金鑰;如果金鑰設有密碼片語,ssh 會要求輸入。
以 ssh 為基礎的工具也接受相同選項:
scp -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps report.tar.gz deploy@203.0.113.10:/tmp/
rsync -av -e "ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps" ./site/ deploy@203.0.113.10:/srv/site/
GIT_SSH_COMMAND="ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_vps" git clone git@example.com:team/repo.git第二跳出現錯誤的原因
使用 ForwardAgent yes 時,代理程式 socket 會在你連線的伺服器上提供。該伺服器上執行的 ssh 命令,會透過轉送的 socket 使用你本機的代理程式及其中的所有金鑰。因此,第一跳正常,但從跳板主機連線到最終伺服器時仍可能出現錯誤。在中間主機上執行 echo $SSH_AUTH_SOCK:顯示 socket 路徑表示可使用轉送的代理程式,而輸出為空則表示沒有。
代理程式轉送還有另一項風險。只要工作階段仍開啟,中間主機上任何具備 root 權限的人都能使用你的代理程式,以你的身分進行驗證。ProxyJump 可同時避免這兩個問題:
ssh -J deploy@jump.example.com deploy@10.0.0.5ProxyJump 會透過跳板主機建立連線,並從你自己的電腦向最終伺服器進行驗證,因此你本機的 ~/.ssh/config 會套用到每一跳,包括 IdentitiesOnly。關閉 ForwardAgent 是強化 VPS 上 SSH 安全性的標準步驟。
伺服器是否應提高 MaxAuthTries?
通常不應該。先查看目前的值:
sudo sshd -T | grep -i maxauthtriessshd -T 會列印包含預設值在內的有效設定,因此即使 sshd_config 未明確設定該值,也能顯示實際值。如果使用 Match 區塊,請加入 -C user=deploy,host=example.com,addr=203.0.113.10,因為這些區塊會針對每個連線評估,否則會被略過。
提高限制確實有效,但僅限於讓行為異常的用戶端有更多嘗試空間:
MaxAuthTries 20驗證檔案後重新載入服務,並在操作期間保持另一個工作階段開啟:
sudo sshd -t
sudo systemctl reload ssh # Debian and Ubuntu
sudo systemctl reload sshd # RHEL family如果在 Ubuntu 24.04 上,systemctl is-enabled ssh.socket 顯示 enabled,表示 sshd 是由 socket 啟用。每個連線都會啟動新的程序,並再次讀取 sshd_config,因此新的連線會自行套用變更。
現在檢查這項變更造成的結果。用戶端正在提供伺服器永遠不會接受的金鑰。提高上限後,伺服器會針對每個連線,以及每個連入網際網路的密碼猜測者,處理 20 個遭拒的金鑰,而不是 6 個。每次提供金鑰都會讓伺服器查詢 authorized_keys。由於正確的金鑰仍排在最後,你自己的登入速度依然很慢。再將第 13 個金鑰加入 agent,就會回到原本的問題,必須再次要求更大的數值。
只有在合法用戶端確實需要提供多個身分時,才提高限制。其他情況都應修正用戶端。當所有使用者都能以已設定的金鑰登入後,降低限制是合理的強化措施,因為較小的數值會讓猜測者在每個連線中可嘗試的次數變少。
為什麼 fail2ban 可能會封鎖你的位址
在預設日誌層級下,sshd 會記錄每次遭拒的公開金鑰驗證:
Failed publickey for deploy from 203.0.113.10 port 51292 ssh2: ED25519 SHA256:AAAA...完整的 agent 發起一次連線時,會在 1、2 秒內從同一個位址產生數行這類日誌。fail2ban 的 sshd jail 會計算 sshd 的失敗日誌行數,當 findtime 內達到 maxretry 時,就會封鎖來源位址。這些時間範圍預設都很短,因此連線設定錯誤時,重試兩次就可能封鎖你自己的位址。
接著,症狀會改變,這也是最容易造成混淆的地方。你不再看到「Too many authentication failures」,而是完全看不到回應:連線會停滯,最後逾時。這是因為防火牆現在會丟棄你的封包,而不是回應連線。原本會顯示錯誤訊息,現在卻變成逾時,這就是訊號;兩者的差異請參閱 SSH 連線遭拒與 SSH 連線逾時的差異。
從供應商的主控台,或使用其他位址,檢查 jail 並解除封鎖:
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 203.0.113.10在處理用戶端問題期間,將你自己的位址加入 jail.local 中的 ignoreip;完成後再移除。jail 本身的設定請參閱 Ubuntu 24.04 的 fail2ban 指南。
一次處理,避免問題再次發生
為每台伺服器在 ~/.ssh/config 中建立專屬的 Host 區塊,並設定 HostName、User、IdentityFile 與 IdentitiesOnly yes。完成後,ssh vps 便能快速輸入,只會提供一個金鑰,即使 agent 中已載入許多金鑰,也不會觸發 MaxAuthTries。這也能讓 ssh -v 的輸出保持簡短,方便在其他問題發生時閱讀。
FAQ
如何立即修正「Too many authentication failures」?
不要一次提供所有金鑰,只提供一把。若要立即連線,請執行 ssh -o IdentitiesOnly=yes -i ~/.ssh/your_key user@host。若要永久修正,請在 ~/.ssh/config 中加入區塊,使用 HostName、User、IdentityFile 指向該金鑰,並設定 IdentitiesOnly yes,然後執行 chmod 600 ~/.ssh/config。使用 ssh -v 確認:應會看到該主機只有一行 Offering public key:。
為什麼使用 ssh -i 仍會提供其他金鑰?
因為 -i 會將 identity 加入清單,而不是限制清單。載入 ssh-agent 的金鑰仍在清單中,也仍會被提供,通常還會排在你指定的金鑰之前。因此,伺服器可能在輪到你的金鑰前,就先觸發 MaxAuthTries。-o IdentitiesOnly=yes 才是限制 ssh 僅使用指定 identity 的選項。請搭配使用 -i 和 -o IdentitiesOnly=yes,或使用 -o IdentityAgent=none,讓該次連線完全忽略 agent。
是否應在伺服器上提高 MaxAuthTries 來修正這個問題?
不應該,幾乎所有情況都是如此。用戶端正在傳送伺服器永遠不會接受的金鑰。提高限制只會讓伺服器在每次連線中,針對每個用戶端及每次抵達伺服器的暴力破解嘗試,評估更多遭拒的金鑰。只要 agent 再載入一把金鑰,問題就會再次發生。若想確認目前的有效值,請使用 sudo sshd -T | grep -i maxauthtries,然後使用 IdentitiesOnly 修正用戶端。
為什麼上個月運作正常的伺服器現在才開始發生這個問題?
因為你的 agent 變得更大。AddKeysToAgent yes 在 ~/.ssh/config 中會讓你使用的每把金鑰保持載入狀態,而桌面 keyring agent 會自行在登入時載入金鑰。載入的金鑰數量超過伺服器的 MaxAuthTries 後,凡是指定金鑰在提供順序中較後面的伺服器,都會開始連線失敗。請執行 ssh-add -l,並將金鑰數量與伺服器上的限制比較。
這會讓我的 IP 位址被 fail2ban 封鎖嗎?
會。每把遭拒的金鑰都會在伺服器日誌中產生一行 Failed publickey for ...,因此一次連線可能在數秒內,從你的位址產生多次失敗;fail2ban 的 sshd jail 會在 maxretry 於 findtime 內達到時封鎖該位址。明顯的徵兆是錯誤變成連線停滯,接著逾時,因為封包遭到丟棄,而不是收到回應。請從主控台使用 sudo fail2ban-client set sshd unbanip <your address> 清除封鎖,並在重新連線前修正用戶端。