🔐 Linux 伺服器防禦第一線:SSH 安全加固、MFA 二階段驗證與 Fail2Ban 實戰
如果你的 Linux 伺服器有對外開 SSH,那它幾乎一定每天都在被掃描、被撞密碼、被嘗試弱口令。 真正能「長期穩定」扛住第一線的做法,不是只做單點設定,而是把三件事串起來: SSH 本體硬化、MFA(二階段驗證)、Fail2Ban 自動封鎖。
這篇會用「能直接上線」的角度,把設定拆成可複製的段落:你照著做完,SSH 的攻擊面會立刻縮小一大截。
✅ 目標與建議路線
| 項目 | 建議設定 | 目的 |
|---|---|---|
| 登入方式 | 只允許 SSH Key(必要時加 MFA) | 直接砍掉「密碼被猜到」這條路 |
| 帳號與來源 | 限制 AllowUsers / AllowGroups,必要時限制來源 IP | 減少可被嘗試的範圍 |
| MFA | 使用 TOTP(Google Authenticator / Authy / 其他 OTP App) | 就算私鑰外洩也多一道門 |
| 暴力破解防護 | Fail2Ban 封鎖失敗登入 IP(含 systemd journal 模式) | 把機器人打到「自己放棄」 |
1) SSH 基礎安全加固(sshd_config)
以下以常見路徑 /etc/ssh/sshd_config 為主。每次修改後,先做語法檢查再 reload。
# 1) 先做語法檢查(很重要)
sudo sshd -t
# 2) 再做 reload(比 restart 安全)
sudo systemctl reload sshd
1-1. 關掉 root 直接登入 + 關掉密碼登入
# /etc/ssh/sshd_config
# 禁止 root 直接登入(建議用一般帳號 + sudo)
PermitRootLogin no
# 關掉密碼登入(核心防線)
PasswordAuthentication no
# 啟用金鑰登入(通常預設就開)
PubkeyAuthentication yes
# 需要 PAM(後面要做 MFA 會用到)
UsePAM yes
如果你有「必須暫時保留密碼登入」的場景,至少也要把允許範圍縮到最小(例如只允許內網、或只允許特定帳號), 等你確認 Key + MFA 都穩了,再把密碼通道關掉。
1-2. 限制可登入的帳號 / 群組
# 只允許這些使用者登入(範例)
AllowUsers admin ops
# 或用群組控管(更好維護)
# AllowGroups sshusers
1-3. 縮短嘗試窗口、降低撞門效率
# 降低暴力破解效率(依需求調整)
MaxAuthTries 3
LoginGraceTime 20
# 保活(避免長連線卡住;也能降低某些資源佔用)
ClientAliveInterval 60
ClientAliveCountMax 2
1-4. 可選:改 Port(降低掃描雜訊)
# 可選:改成高位 Port(不是核心安全,但可降雜訊)
Port 2222
如果你改了 Port,記得同步調整防火牆(firewalld/ufw/nftables)與 Fail2Ban jail 的 port 設定。
2) 加上 MFA(二階段驗證):TOTP(PAM Google Authenticator 模組)
這裡示範「最常見、部署成本最低」的 TOTP:手機 OTP App 掃 QR code 後,每 30 秒產生一次碼。 你也可以換成 Duo、硬體金鑰或公司既有 IdP,但概念相同:把 SSH 的驗證拆成兩道門。
2-1. 安裝套件
Debian / Ubuntu:
sudo apt update
sudo apt install -y libpam-google-authenticator
RHEL / Rocky / Alma(常見作法是啟用 EPEL):
# 先啟用 EPEL(若你環境已啟用可略)
sudo dnf install -y epel-release
# 安裝 Google Authenticator PAM
sudo dnf install -y google-authenticator
2-2. 對要登入的帳號產生 secret(每個帳號都要做一次)
# 用「該使用者」身分執行(不要用 root 代跑)
google-authenticator
跑完後會得到 QR code 與備援碼,請立即存到安全位置(例如密碼管理器)。 OTP 若失效,通常是時間不同步造成的,伺服器務必維持 NTP 正常。
2-3. 設定 PAM:/etc/pam.d/sshd
# /etc/pam.d/sshd
# 加在適當位置(通常在 @include common-auth 之前/附近)
auth required pam_google_authenticator.so
你也可以加上參數(例如允許小幅時間漂移、或允許沒有 secret 的帳號先不套用),但建議上線時採「嚴格」策略。
2-4. 設定 sshd:強制「Key + OTP」,不要再要密碼
重點是兩句:KbdInteractiveAuthentication yes 與 AuthenticationMethods。
這會讓流程變成:先驗證 SSH Key,再跳出 OTP(keyboard-interactive)挑戰。
# /etc/ssh/sshd_config
UsePAM yes
PasswordAuthentication no
# 啟用鍵盤互動(OTP 走這條)
KbdInteractiveAuthentication yes
# 強制同時通過:publickey + keyboard-interactive(OTP)
AuthenticationMethods publickey,keyboard-interactive
套用前請先保留一個已登入的 SSH 連線窗口,並用另一個終端測試登入成功後再 reload sshd。
3) Fail2Ban:把暴力破解「自動封鎖」
Fail2Ban 會分析登入失敗的紀錄(log 或 systemd journal),當某個 IP 在指定時間內失敗次數過多,就自動下防火牆規則封鎖。 你可以把它想成「針對撞門行為的自動反制」。
3-1. 安裝 Fail2Ban
Debian / Ubuntu:
sudo apt update
sudo apt install -y fail2ban
RHEL / Rocky / Alma:
sudo dnf install -y fail2ban
sudo systemctl enable --now fail2ban
3-2. 建議用 jail.d/ 自訂(避免覆寫)
建立一個專門管 SSH 的檔案:
sudo mkdir -p /etc/fail2ban/jail.d
sudo nano /etc/fail2ban/jail.d/sshd.local
範例(偏通用、可直接用):
# /etc/fail2ban/jail.d/sshd.local
[DEFAULT]
# 若系統主要用 systemd journal,建議直接用 systemd backend
backend = systemd
# 忽略白名單(把你的管理來源 IP / VPN 出口加進來)
ignoreip = 127.0.0.1/8
# 失敗統計窗口(10 分鐘內)
findtime = 10m
# 允許失敗次數
maxretry = 5
# 封鎖時間(可用 10m/1h/1d 這種格式)
bantime = 6h
# 依你的系統選擇 banaction(iptables 或 nftables)
# banaction = iptables-multiport
# 若你的系統以 nftables 為主,可改 nftables(不同發行版 action 名稱可能略有差異)
# banaction = nftables
[sshd]
enabled = true
# 若你改 Port,這裡也要跟著改
port = ssh
# Debian/Ubuntu 常見 logpath(若你不用 journal)
# logpath = /var/log/auth.log
# RHEL 系常見 logpath(若你不用 journal)
# logpath = /var/log/secure
3-3. 啟動並檢查狀態
sudo systemctl enable --now fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd
看到 Banned IP list 就表示 jail 正常工作。你也可以直接看 Fail2Ban 自己的 log(多數環境預設在 /var/log/fail2ban.log)。
3-4. 常用操作:解封、手動封鎖、查被封鎖清單
# 查看 sshd jail 狀態
sudo fail2ban-client status sshd
# 解封指定 IP
sudo fail2ban-client set sshd unbanip 203.0.113.10
# 手動封鎖(少用,但排障時會用到)
sudo fail2ban-client set sshd banip 203.0.113.10
4) 上線前最後檢查(我通常會照這份跑)
# SSH 設定語法檢查
sudo sshd -t
# 重新載入(不要急著 restart)
sudo systemctl reload sshd
# 檢查 SSH 監聽(Port 是否正確)
sudo ss -lntp | grep sshd
# 測試:用另一個終端登入(確認流程是 Key -> OTP)
ssh -p 2222 admin@your.server
# Fail2Ban 是否啟用、sshd jail 是否啟用
sudo systemctl status fail2ban --no-pager
sudo fail2ban-client status sshd
5) 進階加分(選做,但很值得)
- 只允許管理網段: 在防火牆 / 雲端 Security Group 限制來源 IP,SSH 不要放全世界。
- 分層管理: 一般帳號登入 + sudo;嚴禁共用帳號;把可登入名單縮到最小。
- 金鑰治理: 強制使用者用密碼管理器保存私鑰 passphrase;定期盤點 authorized_keys。
- 告警與稽核: Fail2Ban 封鎖事件可做寄信/推送;sshd LogLevel 可視需求調高。
💬 留言聊聊:你的 SSH 防護做到哪一層?
我很想知道你目前的環境是:
也歡迎直接貼你的
sshd_config(敏感資訊遮掉)或 Fail2Ban jail 設定,我可以幫你一起檢查是否有風險洞。