保衛 OpenSSH

<<TableOfContents: execution failed [Argument "maxdepth" must be an integer value, not "[1]"] (see also the log)>>

OpenSSH(或者 Secure Shell)以經成為一個取代 telnet 協議作遠端存取用的現有標準。SSH 已經令 telnet 等協議多餘的,當中絕大部份原因是由於連線被加密,以及不再以純文字公開地傳送密碼。

然而,預設的 ssh 安裝並非完美。當你營運一個 ssh 伺服器時,有數個簡單的步驟可以明顯地加固你的安裝。

1. 採用難猜測的密碼/用戶名稱

如果你所營運的 ssh 是對外的,你首先會發現的事情,很可能就是駭客嘗試猜/測用戶名稱/密碼的記錄。駭客一般會掃描連接埠 22(ssh 預設聆聽的連接埠)來找尋執行 ssh 的機器,然後嘗試強行攻擊它。借著使用難猜測的密碼,我們希望任何攻擊在成功前會被記錄底及被留意到。

盼望你已經採用了難猜測的密碼。要不然,請嘗試選擁有以下特徵的密碼:

使用難測密碼的好處並不止於 ssh,它更會影響到系統安全的各個範疇。有關密碼的更多資訊可以在 CentOS 的文檔內找到:

http://www.centos.org/docs/4/html/rhel-sg-en-4/s1-wstation-pass.html

如果你完全沒法阻止你的用戶選用易猜測的密碼,請考慮以隨機產生或難猜測的字串作為用戶名稱。如果壞人不能猜測用戶名稱,他們便不能強加猜測密碼。然而,這只是隱晦資訊來換取安全,所以要留心用戶名稱透過用戶發送的電郵等途徑而被洩漏。

2. 停用 root 登入

SSH 伺服器的設定都儲存在 /etc/ssh/sshd_confg 這個檔案。要停用 root 登入,請確定你有以下一行:

# 阻止 root 登入:
PermitRootLogin no

然後請重新啟動 sshd 服務:

service sshd restart

你果你需要 root 的權限,請登入為一般用戶,然後使用 su 這個指令。

3. 限制用戶登入

SSH 登入可以局限給某些需要遠端存取的用戶。如果你的系統有很多用戶,一個合理的做法就是局限遠端存取給那真正有需要的用戶,藉以減低其他用戶採用易測密碼的影響。在 /etc/ssh/sshd_config 內加入 AllowUsers 一行,以空格隔開用戶名稱。例如:

AllowUsers alice bob

接著請重新啟動 sshd 服務。

4. 停用第 1 類協議

SSH 可以採用兩款協議:第 1 類及第 2 類協議。較舊的第 1 類協議的安全性較低,因此它應該被停用,除非你知道你必須要使用它。請在 /etc/ssh/sshd_config 檔內找尋以下一行,解除註釋,並作出如下修改:

# Protocol 2,1
Protocol 2

然後請重新啟動 sshd 服務。

5. 採用非標準的連接埠

根據預設值,ssh 在連接埠 22 聆聽進入的連線。一個駭客如果要斷定 ssh 是否在你的機器上運行,他最大可能就是掃描連接埠 22。一個有效混淆他的方法就是在非標準的連接埠上運行 ssh。任何未被使用的連接埠都可行,但首選的是 1024 以上的。很多人選用 2222 作為替代的連接埠(它很易記),正如 8080 經常被用作 HTTP 的替代連接埠。正正由於這個原因令它不是個好的選擇,因為任何掃描連接埠 22 的駭客亦不會放過連接埠 2222。隨機地選用一個未被使用的高位連接埠會比較合宜。要進行改動,請在你的 /etc/ssh/sshd_config 檔內加入以下一行:

# 在非標準的連接埠上執行 ssh:
Port 2345  #修改我

然後重新啟動 sshd 服務。請勿忘記在你的路由器及相關的防火牆規則裡作出任何必要的改動。譬如 CentOS 7(或以上)版本,你可以透過複製 firewalld 在 /etc/firewalld/ 內的服務檔,然後更改 ssh 服務的連接埠:

$ cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/ssh-custom.xml

請更改 /etc/firewalld/services/ssh-custom.xml 令連接埠與 ssh 設定檔內的相同:

<port protocol="tcp" port="2345"/>

最後,移除 ssh 服務,新增 ssh-custom 服務,並重啟 firewalld 令改動生效:

$ firewall-cmd --permanent --remove-service='ssh'
$ firewall-cmd --permanent --add-service='ssh-custom'
$ firewall-cmd --reload

又或者在 CentOS 6 上新增 iptable 的規則來開啟新的 ssh 埠:

$ iptables -I INPUT -p tcp --dport 2345 -j ACCEPT

請不要忘記關閉舊的連接埠。

在 CentOS 6 及以上版本,你亦需要更新 selinux,並正確地標籤所選用的連接埠,否則 sshd 便無法存取它。舉個例說:

$ semanage port -a -t ssh_port_t -p tcp 2345 #請更改這處 

因為 ssh 不再在標準的連接埠上聆聽連線,你須要告訴客戶端要連線到哪個連接埠。在指令行上執行 ssh 客戶端時,你可以用 -p 選項來指定連接埠:

$ ssh -p 2345 myserver

又或者如果你使用 konqueror 的 fish 協議,你可用:

fish://myserver:2345/remote/dir

如果你覺得每次連線時都要指定連接埠似乎很痛苦,你只需在你個人的 ~/.ssh/config 檔案裡加入一個指定連接埠的記錄:

 # 客戶端 ~/.ssh/config
Host myserver
HostName 72.232.194.162
        User bob
        Port 2345

~/.ssh/config 必須有以下存取權:

$ chmod 600 ~/.ssh/config

6. 在防火牆過濾 SSH

如果你只須由一個 IP 位址進行遠端存取(例如由辦工室進入家中的伺服器),請考慮在你的路由器或 iptables 內加入一條防火牆的規則,將連接埠 22 的存取權限制到特定的 IP 位址,藉此對連線進行過濾。舉個例說,在 iptables 內你可以用這類型的 iptables 規則(CentOS 6)達至這個目的:

$ iptables -A INPUT -p tcp -s 72.232.194.162 --dport 22 -j ACCEPT

又或者採用 firwalld(CentOS 7)的加強規則局限 ssh 至特定的連接埠。來源位址可以是單一位址或是基本位址及位元遮罩:

# 視乎已啟用及現存的設定,選用 ssh 或 ssh-custom
$ firewall-cmd --permanent --remove-service="ssh"
$ firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="72.232.194.162" service name="ssh-custom" accept'
$ firewall-cmd --reload

SSH 亦對 TCP 包裝函式有內置支援,因此 ssh 服務的存取權亦可同時用 host.allow 及 hosts.deny 來進行管制。

如果你無法限制來源地的 IP 位址,而必須公開 ssh 連接埠,那麼 iptables 依然可以透過記錄及攔截來自同一 IP 位址的重覆登入嘗試,幫助你阻止強行的攻擊。例如透過 iptables:

$ iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name ssh --rsource
$ iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent ! --rcheck --seconds 60 --hitcount 4 --name ssh --rsource -j ACCEPT

第一條規則利用 recent 模塊來記錄每個存取連接埠 22 的新嘗試。第二條規則檢查這個 IP 位址在過去 60 秒內有否嘗試 4 次或以上的連線,若然沒有更接納封包。注意這個規則須要輸入鏈採用 DROP 的預設政策。

如果你在非標準的連接埠上執行 ssh,請不要忘記對連接埠作出相應修改。情況許可的話,利用防火牆進行過濾是一個非常有效的方法來保衛 ssh 伺服器。

那些採用 FirewallD 服務的系統(CentOS 7 或以上)可使用 firewall-cmd# 視乎已啟用及現存的設定,選用 ssh 或 ssh-custom $ firewall-cmd --permanent --remove-service="ssh" $ firewall-cmd --permanent --add-rich-rule='rule service name="ssh-custom" accept limit value="4/m" log' $ firewall-cmd --reload}}} 首個指令移除較寬鬆的的規則,而第二個指令建立一條每分鐘只指納 4 個連線並記錄所有連線的規則。

7. 採用公鑰/私鑰來驗證

採用加密金鑰來驗證提供兩大好處。首先,如果你應用公鑰/私鑰,是方便,因為你不用再輸入密碼(除非你用密碼來保護你的金鑰)。第二,當伺服器能進行金鑰對的驗證,你便可以完全停用密碼驗證,意即存取時靠賴授權的金鑰 —— 因此不再有猜測密碼的嘗試。

建立及在你的 ssh 伺服器上安裝金鑰對是個相對地簡單的過程。

首先,在你會用來連線到伺服器的客戶端上建立一對金鑰(你須要在每台用來連線的機器上這樣做):

$ ssh-keygen -t rsa

這樣做會在你的(隱藏了的)~/.ssh 目錄內建立兩個檔案,名叫:id_rsaid_rsa.pub。第一個檔案:id_rsa 是你的私鑰,而另一個:id_rsa.pub 是你的公鑰。

如果你不想每次連線時都被問及密碼(它是用來解開特定的公鑰),在建立金鑰對的時候,你只須按 enter 作為密碼。建立金鑰對時,是否以密碼加密純粹是你的決定。如何你不將金鑰加密,任何人奪得你的本地機器後,便自動擁有遠端伺服器的 ssh 存取權。此外,本地機器上的 root 能夠存取你的金鑰:但假若你不能信任 root(或者 root 已被攻佔),你已經大禍臨頭。將金鑰加密捨棄了不用密碼的 ssh 伺服器,來換取額外的安全,得來的就是輸入密碼來使用這條金鑰。你可利用 ssh_agent 這個程式進一步簡化這個程序。

現在為你的私鑰設定權限:

$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/id_rsa 

請將公鑰(id_rsa.pub)複製到伺服器上,然後安裝它在 authorized_keys 清單內:

$ cat id_rsa.pub >> ~/.ssh/authorized_keys

註:一旦你匯入了公鑰,你可以在伺服器上刪除它。

最後,設定伺服器上的檔案權限:

$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys

如果 /etc/ssh/sshd_config 內的 StrictModes 被啟用(預設值),以上的權限是必須的

請確保你已設置正確的 SELinux 脈絡:

$ restorecon -Rv ~/.ssh 

現在當你登入伺服器的時候,你便不用再輸入密碼(除非你在建立金鑰對的時候輸入了一個密碼)。ssh 預設是會先利用金鑰進行驗證。如何它找不到金鑰,或驗證失敗,ssh 會回落到平常的密碼驗證。

一旦你檢查過可以用金鑰對來登入伺服器,你可以在你的 /etc/ssh/sshd_conf 檔內加入以下設定來停用密碼驗證:

# 停用密碼驗證,強制使用金鑰
PasswordAuthentication no

8. 常見問題(FAQ)

問:CentOS 採用 X 版的 OpenSSH,而最新版本是 Y 版。X 版藏有一個嚴重的安全性漏洞,我應否升級?

答:不應該。上游供應者有一個政策,會將最新版本的安全性修正反向移植到現有的發行版本內。只要你擁有最新的更新,你的 CentOS 發行版本已經得到全面修正。有關反向移植安全性修正的詳情,請參閱這裡:

http://www.redhat.com/advice/speaks_backport.html

問:我如何令 ssh 容讓以 NFS 共享用戶主目錄的機器採用無密碼的驗證?

答:SELinux 預設攔阻 root 存取以 NFS 共享、非公用的目錄及檔案,因此 ssh 無法讀取 ~/.ssh 內的用戶金鑰檔。若要批準存取權,請用以下指令更改 use_nfs_home_dirs 的設定值:

setsebool -P use_nfs_home_dirs 1 

https://www.centos.org/forums/viewtopic.php?t=49194

9. 連結

http://www.centos.org/docs/5/html/Deployment_Guide-en-US/ch-openssh.html

http://www.dragonresearchgroup.org/insight/sshpwauth-tac.html

Translation of revision 54

zh-tw/HowTos/Network/SecuringSSH (last edited 2019-12-09 09:11:31 by anonymous)