如何加固 SSH 伺服器設定
最後更新:
sshd_config 這一個文字檔,就是你的 SSH 伺服器的全部安全姿態——而在多數系統上,它出廠時的狀態是為相容性最佳化的,不是為安全:密碼登入預設開啟、root 只要用金鑰就能登入、閒置工作階段永不逾時、伺服器提供的演算法取決於多年前安裝的那個 OpenSSH 版本。加固它不是照抄一份 2021 年的清單:演算法會被移除、預設值會變、五年前堪稱典範的設定今天可能已經薄弱。本文講清每一項改動實際做了什麼、決策順序為什麼重要、以及如何測試新設定而不把自己鎖在門外。你可以在SSH 伺服器設定稽核裡逐行稽核自己的檔案——對照 2026-11-13 的基準,全程在瀏覽器本地完成。
預設值是起點,不是加固姿態
OpenSSH 的預設值是為了讓全新安裝對盡可能多的人開箱即用而選的——這正是它們不是安全姿態的原因。按 sshd_config 手冊頁記載的目前預設值,包括 PasswordAuthentication yes、PermitRootLogin prohibit-password、MaxAuthTries 6、LoginGraceTime 120 秒,以及 ClientAliveInterval 0,即閒置工作階段永不終止。這些都不是 bug:每一項都是有意的相容性選擇,而每一項在加固稽核裡都是一條發現。
實際後果是,一台從未加固過的伺服器仍然可以被密碼猜解、仍然接受用被盜金鑰的 root 登入、仍然讓被遺棄的工作階段無限期開著。預設值還會隨時間變化——OpenSSH 10.6 出廠的預設值和 OpenSSH 7 的並不一樣——所以「我什麼都沒改過」並不是一個中性陳述,它的意思是你的安全姿態就是恰好裝上的那個版本所決定的,而要知道它是什麼,只能去讀這個檔案。這是稽核的第一項工作:讓看不見的預設值現形,因為檔案中沒有出現的指令依然在生效。
關掉密碼,比換連接埠管用得多
sshd_config 裡最有效的一處改動是 PasswordAuthentication no 加上 PubkeyAuthentication yes:從這一刻起,任何密碼——猜到的、外洩的、釣到的——都打不開工作階段,因為守護行程不再接受這種證明方式。金鑰驗證把攻擊從「猜一個人想出來的秘密」變成了「偷一個從不經過網路的私鑰檔案」,這就是為什麼包括 Mozilla 在內的每一份加固基準都從這裡開始。如果本文只能帶走一句話,就是這句:先產生一對金鑰(見SSH 金鑰套件和配套文章SSH 金鑰詳解)、裝好公鑰、確認能用金鑰登入,然後再關掉密碼。
相比之下,把連接埠從 22 換成一個冷門連接埠不是加固——只是隱蔽。它能減少日誌裡的噪音,因為多數全網掃描只敲 22 連接埠,但它攔不住任何一個願意掃連接埠的攻擊者:一次連接埠掃描幾秒鐘就能找到守護行程,而它背後的強度完全取決於設定。因此稽核只把非 22 連接埠當作提示資訊,絕不計分。關掉密碼之前還有一個坑值得知道:在使用 PAM 的系統上,光設 PasswordAuthentication no 是不夠的——鍵盤互動驗證仍可能讓 PAM 接受密碼,所以 /etc/pam.d/sshd 裡的 PAM 堆疊也必須拒絕密碼。Mozilla 的指南明確寫了這一點,而這是最常被漏掉的另一半。
Root 登入:prohibit-password 實際允許什麼
PermitRootLogin 有四個取值,它們之間的差別就是有沒有稽核軌跡的差別。預設值 prohibit-password 允許 root 登入——只是不許用密碼。被盜的 root 金鑰照樣長驅直入,而一旦工作階段成了 root,日誌裡就再也分不清是哪位管理員。Mozilla 的 Modern 設定把它設為 No,這才是加固的答案:root 根本不應該是一個登入帳號。用具名使用者登入,再用 sudo,這樣每一次特權操作都能歸屬到具體的人。
中間值存在是有原因的,值得了解而不是害怕。forced-commands-only 只允許在 authorized_keys 裡限定了單一命令的金鑰以 root 登入——備份和監控指令碼用的就是這個模式——是對自動化而言合理而有意的選擇。而 yes 絕不合理:它允許 root 用密碼登入,在任何稽核裡都是錯誤。實用的規則是:如果有人以 root 登入,設定就是錯的;如果是指令碼,就把金鑰限定到一條命令,並在註解裡寫明,否則下一個讀檔案的人會把它當成問題「修掉」。
演算法廢棄是一個移動靶
你設定裡的演算法有保存期限,而且比你想的短。OpenSSH 10.0(2025-04-09 發布)徹底移除了 DSA(ssh-dss)支援,把有限域 Diffie-Hellman 從伺服器預設金鑰交換裡拿掉,並把後量子混合演算法 mlkem768x25519-sha256 設為預設金鑰協商。一份從 2021 年部落格抄來的設定,可能還列著 diffie-hellman-group1-sha1、3des-cbc、arcfour 或 hmac-md5——在現代稽核裡這些全是錯誤,其中一些連裝好的守護行程都不再支援。設定沒有變,世界變了。
所以加固基準必須帶上日期,而重新檢查是工作的一部分,不是事後想起來的事。Mozilla 的 Modern 設定——curve25519 金鑰交換、chacha20-poly1305 與 AES-GCM 加密、SHA-2 的先加密後認證(EtM)MAC——是參照標準,但它成文時還沒有 OpenSSH 10.0 設為預設的後量子金鑰交換,所以 2026 年的稽核在它之外也接受 mlkem768x25519-sha256 與 sntrup761x25519-sha512。保持跟進的習慣很便宜:每年一兩次,在伺服器上跑 ssh -Q kex、ssh -Q cipher 和 ssh -Q mac,看看裝好的版本實際提供什麼,對照最新的 Mozilla 指南,再用稽核工具對同一份檔案重跑一次。2021 年的滿分成績是歷史文件,不是現況。
Match 區塊與 Include:讓「乾淨」稽核說謊的兩種方式
設定檔不是一串平鋪的設定——它是一個帶條件分支的程式,而其中兩個特性會讓一份讀起來很安全的設定表現得並不安全。第一個是 Match 區塊:Match User、Match Group 或 Match Address 區塊裡的指令只在條件滿足時生效,手冊頁明確寫著,如果某個關鍵字出現在多個滿足條件的 Match 區塊裡,只套用第一次出現的那個。全域寫了 PasswordAuthentication no、後面卻有個 Match 區塊悄悄給某個群組重新開啟密碼,是真實存在的設定,而逐行閱讀恰恰最容易漏掉它。Match 區塊內的發現是有條件的,絕不是全域的,誠實的稽核必須這樣標註。
第二個是 Include。現代發行版會把 sshd_config 拆成多個檔案——通常是 /etc/ssh/sshd_config.d/*.conf——Include 指令按字典序在它出現的位置把這些檔案拉進來,而在多數發行版上它就位於檔案頂部。因為先取到的值獲勝,寫在被包含檔案裡的指令會遮住主檔案後面相同的指令:你讀到的那一行並不是起作用的那一行。在瀏覽器裡運行的稽核工具無法跟隨 Include——那些檔案不在你的機器上——所以它會把 Include 標為「未跟隨」並列出路徑。稽核時要審整個目錄,而不只是一個檔案;還要記住,重複的指令不是可以忽略的筆誤:第一個獲勝,第二個是死文字,只會迷惑下一個編輯檔案的人。
安全上線:先測試,再關門
每一次 sshd_config 改動都帶著同樣的風險:一個拼寫錯誤會讓守護行程拒絕重啟,而一個語法正確但設定錯誤的改動會拒絕你本人。避開兩者的上線流程很短,而且沒有商量餘地:先用 sshd -t 檢查語法再動運行中的服務——它只解析檔案並報告錯誤,不會啟動任何東西。然後重啟或重新載入守護行程,再測試。絕不要一邊改設定一邊關掉自己唯一的工作階段。
測試本身就是紀律:保持現有工作階段開著,再開第二個工作階段,用新規則全新登入一次。第二次登入成功,改動就是安全的,可以關掉第一個工作階段;不成功,開著的工作階段就是你的退路,可以改回檔案並重新載入。對於無法親自到場的伺服器,改動還應該一次只做一項——壞掉的金鑰檔案加上被停用的密碼方式放在同一次編輯裡,就沒有任何退路了。稽核工具可以基於你的檔案產生一份加固版作為起點,但那是需要逐個 Match 區塊審閱、用 sshd -t 測試的草稿,絕不是可以直接丟進去的檔案。