OpenSSH
早期主機使用遠程登錄的協議是telnet,TCP/23(telnet是基於TCP的23號端口的)
telnet有兩大缺陷:
1、用戶認證過程是明文的;
2、數據傳輸是明文的;
因此telnet不再使用了。於是就出現了ssh。
1、ssh
ssh(Secure SHell,安全的shell),與telnet一樣,也是一種遠程登錄協議,但其與telnet的實現機制不同,ssh為TCP/22(基於TCP協議的22號端口)。
與telnet一樣,ssh是基於C/S架構的。在服務器端,需要運行服務器軟件,監聽在某個端口(套接字上)。客戶端發起連接請求,服務器端在收到請求后響應客戶端請求,雙發建立數據傳輸的通道,並一直處於連接狀態,當所有用戶請求處理完成之后再退出。因此需要專門的客戶端軟件和服務器端軟件。
ssh在剛剛誕生時,出現了一款軟件,但后來商業化了。於是就出現了基於ssh運行在Linux/Unix上的開源軟件OpenSSH(Open:開源的意思)。
ssh主要有v1,v2兩個版本,通過驗證發現,v1版本存在致命的缺陷,無法有效的拒絕中間人攻擊,這個缺陷非常致命,到目前為止,v1處於廢棄狀態;最好是使用v2,但由於許多古老的設備上還在使用v1,因此不得不使得客戶端能夠訪問v1的服務。(新購的設備盡量拒絕v1版本的協議)而OpenSSH對兩種版本的協議都提供了支持。
1.1、ssh服務器端
SSH無法實現Windows上的服務器端,故此處的服務器端指的是工作在Unix/Linux的服務器端。名稱為sshd(OpenSSH提供的)。
服務器端也是一個可執行程序,只不過這個可執行程序直接工作在后台。而且不會退出,一旦退出服務即終止。
1.2、OpenSSH包含的兩個組件
ssh(客戶端工具,命令行的)、sshd(服務器端工具)
2、SSH認證的實現和實現加密數據傳輸的簡要概述
sshd:主機密鑰
ssh服務器端需要一個主機密鑰(第一次向服務器發送一個請求時,對方總是需要我們確認一個東西(對方發來一個東西,詢問是否接受),這個信息就是主機密鑰)。
那么那么為什么需要主機密鑰呢?若通信的雙方此前從來沒有通信過,那么如何建立安全通信呢?此前我們討論過,需要借助於CA證書,但SSH客戶端和服務器端都未必有證書。因此沒有辦法驗證對方身份的可靠性,在此前提下,服務器端會向客戶端發送一個主機公鑰,我們的客戶端就會接收對方主機公鑰的指紋信息,接下來客戶端會被詢問是否認可這個指紋,此時就需要客戶端(用戶)自己確認這個服務器是否是你認可的服務器(因為沒有任何有效的措施能夠確認對方身份,只能憑借用戶自己的判斷)。因此client回答yes就表示就此接受了對方主機公鑰,這個公鑰是主機上一對密鑰的公鑰信息。
具體過程如下所示:
客戶端通過遠程連接進行身份認證時,需要將賬號密碼加密后傳輸至服務器端,在傳輸過程中,賬號密碼存在被竊取的風險。因此SSH還支持另外一種認證方式。SSH認證方式分為以下兩種:
- 基於口令的認證:默認情況下都是基於口令的認證;
- 基於密鑰的認證:客戶端用戶自身也生成一對密鑰,它把公鑰放在服務器上的某個家目錄下(這個公鑰信息必須嚴格保密,不能讓任何第三方知道),私鑰自己保留。以后遠程登錄這台服務器時,不再要求輸入密碼,而是傳輸數據時用對方的公鑰加密數據,若對方能用私鑰將數據解密即配對成功,此時不再需要口令。但基於密鑰的認證需要事先配置。
3、注意(基本安全技巧)
- 基於口令的認證存在風險,在認證時輸入用戶名root和密碼之后,有可能被第三方暴力將密碼破解,因此,一般不允許使用root用戶直接在基於ssh的客戶端登錄,若一定要使用root用戶,只能通過登錄普通用戶后再su過去的方式實現。口令認證時位於互聯網上的服務器最后一道也是唯一一道防線;
- 並且為了安全起見,也需要對普通用戶登錄的主機進行限制,若一定要在不被信任的主機上遠程登錄,則需要通過一台VPN服務器,先連接到VPN服務器上,再由VPN服務器轉連;
- 更重要的是,最好不要使用22號端口進行遠程登錄,因為22號端口默認為遠程登錄端口,易被監控暴力破解;可以換一個端口使得別人無從揣測;
- 遠程登錄與系統安全性密切相關,怎么強調其安全性都不為過;
- 經常換密碼(一般一個月換一次,最好密碼是隨機的並且足夠長)
4、OpenSSH配置詳解
在RedHat系列的系統上,ssh是由多個rpm包組成的rpm服務。這多個rpm包有的是提供客戶端的,有的是提供服務器端的,有的是提供通用組件的。如下所示:
上圖中:
openssh-server-...:服務器端
openssh-clients-...:客戶端
openssh-5.3p2-...:通用組件庫
openssh-askpass-...:建立會話時用到的工具和庫文件
4.1、獲取服務的運行狀態:(如果當前有22號端口表明,ssh服務處於已經啟動並工作的狀態)
netstat -tnl(-t表示當前主機上根TCP建立連接的所有會話,-n表示以數字的方式顯示IP地址和端口,-l表示顯示處於監聽狀態(客戶端已經啟動並等待與客戶端連接的狀態)的服務)
netstat
-r:顯示路由表
-n:
-t:TCP connection
-u:UDP connection
-l:listening
-p:process,哪一個進程或程序監聽了當前這個服務
獲取sshd服務運行狀態的另外一種方法:
4.2、配置文件詳解
ssh客戶端和ssh服務器端都需要配置文件:
/etc/ssh目錄下:
客戶端ssh配置文件:/etc/ssh/ssh_config
服務器端sshd配置文件:/etc/ssh/sshd_config
moduli:ssh中用到的密鑰交換的相關信息
v1版本主機密鑰對:ssh_host_key,ssh_host_key.pub
v2版本主機密鑰對:
DSA算法:ssh_host_dsa_key,ssh_host_dsa_key.pub
RSA算法:ssh_host_rsa_key,ssh_host_rsa_key.pub
主機密鑰是ssh會話建立的根本前提,至關重要。
此處也反映了Linux的哲學思想之一:使用文本文件保存程序的配置信息。
sshd_config配置文件解釋:
man sshd_config #獲取幫助文檔信息
sshd服務的任何改變配置要想其生效需重啟服務(腳本服務在/etc/init.d/sshd)
service sshd {start|stop|restart|reload|force-reload|condrestart|try-restart|status}
#后帶空格表示注釋,#后不帶空格表示可用選項;
Port:指定服務的端口號;
Protocol:啟用的協議版本(默認優先使用v2版本);
AddressFamily:表示若當前主機同時啟用了IPv4和IPv6的地址,那么打算在哪一類地址上啟用ssh服務,any表示IPV4,IPV6都可以;
ListenAddress:表示監聽在哪一個地址上(若當前主機配置了兩個個IP地址,只需要其中一個提供服務,需要手動指定,若不指定,默認兩個都提供服務。0.0.0.0表示任意地址,當前主機配置了哪個地址,哪個地址就能提供服務,配置了多個地址就在每一個地址上提供服務,否則手動指定);
HostKey:指定密鑰;
KeyRegenerationInterval:客戶端臨時密鑰生成的間隔時間,間隔指定時間后重新生成密鑰;
ServerKeyBits:服務器端密鑰長度;
SyslogFacility:指定哪一個facility記錄日志;
LogLevel:日志級別;
LoginGraceTime:登錄時的寬容時間(登錄時等待登錄的時間,不登錄則強行退出);
LoginGraceTime:是否允許管理員直接登錄;
StrictModes:是否使用嚴格限定模式(不重要);
MaxAuthTries:最大登錄次數;
RSAAuthentication:是否支持RSA密鑰認證(基於RSA機制的密鑰認證);
PubKeyAuthentication:基於密鑰的認證(如果啟用,客戶端會生成一對密鑰,公鑰會放在服務器端的某個家目錄下);
AuthroizedKeysFile:指定客戶端公鑰文件存放的家目錄的文件路徑;
RhostRSAAuthentication:主機認證(指的是是否信任對方主機,接下來就不需要登錄了而是直接使用,不安全);
PasswordAuthentication:是否允許基於口令的認證;
ChallengeResponseAuthentication:是否使用挑戰式握手協議認證(不安全,一般不允許使用);
UsePAM:是否使用UsePAM(這是一種可插入式認證模塊,一般都是啟用的);
X11Forwarding:是否轉發X11請求;
PrintMotd:在用戶登錄是是否打印/etc/motd文件的內容;
PrintLastLog:在登錄時是否顯示哪個主機在什么時候登錄過(不推薦顯示,會為不法用戶提供信息,在互聯網上,這種信息越少出現越好,最好軟件版本號都不應該提供);
Banner:歡迎標語(用戶登錄SSH時會將指定文件的內容當做歡迎標語為用戶打印一次,啟用后建立一個文件,文件路徑在此處指定,登錄后會顯示文件中的信息);
Subsystem:(將ftp基於SSH實現叫做sftp,將ftp基於SSL實現叫做ftps)指定sftp的服務器程序,只要指定的程序存在即可默認啟動。
ssh客戶端工具的使用:
ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname [command]
常用命令組合:
ssh -l USERNAME REMOTE_HOST ['COMMAND']
ssh USERNAEM@REMOTE_HOST ['COMMAND']
-p port:指定端口
-X:登錄到遠程主機上,並且能夠執行遠程主機的窗口命令,因為這些窗口要在本地顯示,因此,本地必須是圖形化的
-Y:功能與-X一樣,單比-X更安全
在第一次遠程登錄接受了密鑰之后,系統會認為這是可信任的主機,因此它會將主機的密鑰信息添加到可信任主機列表中。每個用戶只要登錄過遠程主機,在當前用戶的家目錄下會生成一個.ssh文件夾,文件夾中有一個knows_host文件,任何時候接受了主機,哪個主機的公鑰信息就會保存在這個文件中。因此當第二次進行遠程登錄時,會將文件中的公鑰與遠程主機的私鑰一建立會話測試是否能匹配上,若配對成功,表示認可了對方主機,因此就不需要進行密鑰接受了。(此過程信任是單向的)
SSH支持不登錄遠程主機但卻可以在遠程主機上執行命令,並將命令的執行結果返回到本地。只需在命令的最后加上可執行命令即可。
5、基於密鑰的認證的實現:
需要一台主機作為客戶端(前提是基於某個用戶實現):
(1).生成一對密鑰
ssh-keygen
-t [指定加密算法rsa或dsa](生成的密鑰默認保存在用戶家目錄下面的.ssh/id_rsa和.ssh/id_rsa.pub)
-f /path/to/keyfile:指定生成的私鑰文件目錄
-N 'password':指定密碼為password
注:.ssh的權限為700,若大於700,.ssh將無法使用。
(2).將生成的公鑰傳輸至服務器端某用戶及目錄的.ssh/authrorized_keys文件中(可與當前用戶不一致)
方法一:使用文件傳輸工具實現,專用命令:ssh-copy-id
ssh-copy-id -i /path/to/pubkey(公鑰文件位置) USERNAME@ROMATE_HOST(既復制又能追加到文件尾部)
方法二:ssh另外一個重要的客戶端工具scp(基於ssh的遠程復制命令,能夠在主機之間傳輸數據(因為是基於ssh傳輸,因此傳輸與過程是加密的))
scp [opetions] SRC DEST
-r:遞歸復制目錄
-p:保存權限
-a:相當於-rp
SRC或DEST為REMOTE_MACHINE(遠程主機)時的格式:
USERNAME@HOSTNAME:/path/to/somefile
scp的實現是需要先復制到臨時文件中,再將臨時文件使用cat 文件名 >> 目標文件 追加到文件中
(3).測試登錄即可
sftp:基於SSH的ftp,既是客戶端又是服務器端,數據傳輸過程是加密的;
sftp USERNAME@IP #連接遠程主機
下載文件到本地:get /path/to/somefile
多個文件使用mget;
總結:
1.密碼應該經常切換且足夠復雜;
2.使用非默認端口;
3.限制登錄的客戶端地址;
4.禁止管理員直接登錄;
5.僅允許有限用戶登錄;
6.使用基於密鑰的認證;
7.不要使用版本1;
嵌入式系統專用的ssh軟件:dropbear(可安裝測試使用)