SSH 概述#
SSH 是一种协议#
- Secure Shell(安全外壳协议,简称 SSH)是一种加密的網絡傳輸協議。
- SSH 通過在網絡中創建安全隧道來實現 SSH客戶端與服務器之間的_連接_。
- SSH 最常見的用途是遠程登錄系統,人們通常利用 SSH 來傳輸命令行界面和遠程執行命令。
OpenSSH 開放源代碼版本#
OpenSSH 是安全 Shell (SSH) 工具的開放源代碼版本,Linux 及其他非 Windows 系統的管理員使用此類工具跨平台管理遠程系統。
常見的 SSH 工具#
名稱 | 描述 | 支持平台 | 推薦 |
---|---|---|---|
PuTTY(Free Windows) | 免費開源的 SSH 終端工具 | Windows | ⭐⭐⭐ |
WinSCP | SCP 協議的文件傳輸工具 | Windows | ⭐⭐⭐⭐⭐ |
FileZilla | 多協議文件傳輸工具 | Windows Linux MacOS | ⭐⭐⭐⭐ |
MobaXterm | 免費開源的 SSH 終端工具 | Windows | ⭐⭐⭐⭐ |
Termius | 全平台 SSH 終端工具 | Windows Linux MacOS Android IOS | ⭐⭐⭐⭐⭐ |
SSH 協議工作原理#
SSH 協議框架中的三個子協議#
-
傳輸層協議 SSH-TRANS
提供服務器驗證、完整性和保密性功能,建立在傳統的 TCP/IP 協議之上。
-
驗證協議 SSH-USERAUT
向服務器驗證客戶端用戶,有基於用戶名密碼和公鑰兩種驗證方式,建立在傳輸層協議 SSH-TRANS 之上。
-
連接協議 SSH-CONNECT
將加密隧道復用為若干邏輯信道。它建立在驗證協議之上。
SSH 工作流#
透過 Wireshark 抓 包分析各個階段#
TCP 三次握手#
SSH 服務器端在 22 端口偵聽客戶端的連接請求,接收到客戶端的連接建立請求後,與客戶端進行三次握手,建立起一條 TCP 連接,後續的所有報文交互都在這個 TCP 連接之上進行。
版本協商#
服務器和客戶端都會向對端發送自己支持的版本號。服務器端和客戶端收到對端發送過來的版本後,與本端的版本號進行比較,雙方都支持的最高版本號即為協商出的版本號。
算法協商#
- 客戶端和服務器端都將自己支持的算法列表發送給對方;
- 雙方依次協商每一種算法(密鑰交換算法、加密算法等)。每種算法的協商過程均為:從客戶端的算法列表中取出第一個算法,在服務器端的列表中查找相應的算法,如果匹配上相同的算法,則該算法協商成功;否則繼續從客戶端算法列表中取出下一個算法,在服務器端的算法列表中匹配,直到匹配成功。如果客戶端支持的算法全部匹配失敗,則該算法協商失敗。
- 某一種算法協商成功後,繼續按照上述方法協商其他的算法,直到所有算法都協商成功;如果某一種算法協商失敗,則客戶端和服務器之間的算法協商失敗,服務器斷開與客戶端的連接。
在algorithms
包含了所有需要協商的算法
NO. | 描述 | 解釋 |
---|---|---|
1 | kex_algorithms | 密鑰交換算法 Key Exchange,裡邊包含了 D-H 算法,用於生成會話密鑰 |
2 | server_host_key_algorithms | 服務器主機密鑰算法 Host Key,用於生成密鑰對 |
3 | encryption_algorithms_client_to_server | 對稱加密算法,常用的有aes128-cbc,3des-cbc |
4 | mac_algorithms_client_to_server | Mac 算法,主要用於保證數據完整性 |
5 | compression_algorithms_client_to_server | 壓縮算法 |
密鑰交換#
客戶端生成一個臨時密鑰 ephemera- public key 發送給服務器端 **【??】**
服務端與客戶端使用 Diffie-Hellman 算法生成會話密鑰 Session key。
在這個包中,服務器端將主機密鑰 Host Key、會話密鑰 Session key、簽名等一同發送給客戶端。
客戶端回覆一個 New Key,接下來進入加密通信。
接下來的會話過程全程加密,從抓包中已經看不到任何明文信息了。
用戶認證#
- 客戶端向服務器端發送認證請求報文,其中攜帶的認證方式為 “none”。
- 服務器收到 none 方式認證請求,回覆認證挑戰報文,其中攜帶服務器支持、且需要該用戶完成的認證方式列表。
- 客戶端從服務器發送給自己的認證方式列表中選擇某種認證方式,向服務器發起認證請求,認證請求中包含用戶名、認證方法、與該認證方法相關的內容:
- 密碼認證方式中,內容為用戶的密碼;
- 公鑰認證方式中,內容為用戶本地密鑰對的公鑰部分(公鑰驗證階段)或者數字簽名(數字簽名驗證階段)。
- 服務器接收到客戶端的認證請求,驗證客戶端的認證信息:
- 密碼認證方式:服務器將客戶端發送的用戶名和密碼信息,與設備上或者遠程認證服務器上保存的用戶名和密碼進行比較,從而判斷認證成功或失敗。
- 公鑰認證方式:服務器對公鑰進行合法性檢查,如果不合法,則認證失敗;否則,服務器利用數字簽名對客戶端進行認證,從而判斷認證成功或失敗。
- 服務器根據本端上該用戶的配置,以及用戶認證的完成情況,決定是否需要客戶端繼續認證,分為以下幾種情況:
- 如果該種認證方式認證成功,且該用戶不需要繼續完成其他認證,則服務器回覆認證成功消息,認證過程順利完成。
- 如果該種認證方式認證成功,但該用戶還需要繼續完成其他認證,則回覆認證失敗消息,繼續向客戶端發出認證挑戰,在報文中攜帶服務器需要客戶端繼續完成的認證方式列表;
- 如果該種認證方式認證失敗,用戶的認證次數尚未到達認證次數的最大值,服務器繼續向客戶端發送認證挑戰;
- 如果該種認證方式認證失敗,且用戶的認證次數達到認證次數的最大值,用戶認證失敗,服務器斷開和客戶端之間的連接。
服務請求#
SSH 協議支持多種應用服務。用戶成功完成認證後,SSH 客戶端向服務器端發起服務請求,請求服務器提供某種應用。
服務請求的過程為:
- 客戶端發送
SSH_MSG_CHANNEL_OPEN
消息,請求與服務器建立會話通道 session; - 服務器端收到
SSH_MSG_CHANNEL_OPEN
消息後,如果支持該通道類型,則回覆SSH_MSG_CHANNEL_OPEN_CONFIRMATION
消息,從而建立會話通道; - 會話通道建立之後,客戶端可以申請在通道上進行 shell 或 subsystem 類型的會話,分別對應 SSH 和 SFTP 兩種類型的服務。
SSH 協議安全性機制#
加密通道#
所謂加密通道,是指發送方在發送數據前,使用加密密鑰對數據進行加密,然後將數據發送給對方;接收方接收到數據後,利用解密密鑰從密文中獲取明文。
加解密算法分為兩類:
- 對稱密鑰算法:數據加密和解密時使用相同的密鑰和相同的算法。
- 非對稱密鑰算法:數據加密和解密時使用不同的密鑰,一個是公開的公鑰,一個是由用戶秘密保存的私鑰。
由於非對稱密鑰算法比較耗時,一般多用於數字簽名以及身份認證。SSH 加密通道上的數據加解密使用對稱密鑰算法,目前主要支持的算法有 DES、3DES、AES 等,這些算法都可以有效地防止交互數據被竊聽,而且由於採用了初始化向量保護,可以防止類似於密碼流復用等密碼分析工具的攻擊。
密鑰交換算法#
對稱密鑰算法要求解密密鑰和加密密鑰完全一致,才能順利從密文中解密得到明文。因此,要建立加密通道,必須先在通信雙方部署一致的加解密密鑰。部署加解密密鑰的方式有多種:手工配置和第三方機構分配等。手工配置的方式擴展性差,只適合一些小型的本地網絡;使用第三方機構分配密鑰的方式,需要額外的第三方服務器,而且密鑰在網絡中傳輸容易被竊聽。
SSH 協議使用一種安全的方式在通信雙方部署密鑰:密鑰交換算法。利用密鑰交換算法可以在通信雙方動態產生密鑰,這個密鑰只能被通信的雙方獲得,任何第三者都無法竊聽,這就在源頭上保證了加解密使用密鑰的安全性,很好地解決了密鑰分發問題。
密鑰交換算法的基本原理#
- 客戶端隨機選擇一個私鑰 ,計算出 ,將計算出的 發送給服務器端。其中, 是一個很大的素數, 是 的素根。 和 是雙方共有的一對參數,協議允許雙方通過協商獲得相同的 和 參數。
- 服務器也隨機生成一個私鑰 ,計算出 ,也將計算出的 發送給客戶端。
- 服務器接收到客戶端發送過來的,按照下面的公式計算出密鑰:
- 客戶端收到服務器端發送過來的 ,同樣按照下面的公式計算出密鑰:
通過上面的方法,客戶端和服務器端就可以獲得相同的密鑰。
由上面的分析可以看出,密鑰交換算法的安全性建立在計算離散對數的難度之上。算式中,由 X 計算 Y 是很容易的,但是要由 Y 計算 X 是非常困難的。在密鑰交換算法中對外公開的只有 、、 和,私鑰和是保密的,其他用戶即便獲取了 、、 和也很難推斷出私鑰和,從而保證了密鑰的安全性。
密鑰交換算法具有如下優勢:
- 擴展性更好,不需要網絡管理員的多餘配置;
- 交換得到的密鑰是保存在內存中,不易被讀取和篡改;
- 每個連接都會動態生成一次新的密鑰,安全性更高。
用戶認證機制#
基於密碼的安全驗證#
使用自動生成的公鑰 - 私鑰對來簡單地加密網絡連接,隨後使用密碼認證進行登錄。具體過程如下:
- 客戶端發送登錄請求,
ssh user@hostname
- 服務器接受請求,將服務器的公鑰 server_rsa.pub 發送給客戶端
- 客戶端輸入密碼,密碼使用 server_rsa.pub 加密後發送給服務器(敏感信息安全傳輸)
- 服務器接受加密後的密碼,使用服務器私鑰 server_rsa 解密,匹配認證密碼是否合法
至此,身份認證通過,然後是交換會話密鑰(對稱加密)
- 客戶端生成會話數據加密 session_key, 使用 server_rsa.pub 加密後傳輸給服務器(會話密鑰)
- 服務器獲取到後使用 server_rsa 解密,得到 session_key
使用會話密鑰對之後傳遞的數據進行加密。注:使用對稱加密效率高。
- 客戶端和服務器通過 session_key 進行會話數據安全傳輸
但是,這種認證方式無法避免中間人攻擊,可能會有別的服務器在冒充真正的服務器。
公鑰身份認證#
客戶端生成一對公鑰和私鑰,並將自己的公鑰複製到服務器上。客戶端請求登錄的時候,服務器會隨機生成一個字符串並用客戶端的公鑰進行加密,客戶端收到之後用自己的私鑰解密後,再發送給服務器。服務器收到後進行比對,如果比對成功,就證明用戶是可信的,直接允許登錄,不再要求密碼。從而避免了中間人攻擊。具體過程如下:
基於密鑰的安全驗證簡單的描述如圖中所示。但在實際傳輸過程中所有的數據都是需要加密以保證數據傳輸安全,即同樣會生成會話密鑰,使用會話密鑰對傳輸數據進行加密的過程。詳細過程如下:
- 客戶端發送登錄請求,
ssh user@hostname
- 服務器接受請求,將服務器的公鑰發送給客戶端
- 服務器生成會話 ID (session id),設為 ,發送給客戶端。
- 客戶端生成會話密鑰 (session key),設為 ,並計算
- 客戶端將 用 進行加密,結果發送給服務器
- 服務器用服務器私鑰進行解密,獲得
- 服務器進行 的運算,獲得
至此,服務器和客戶端都知道了會話密鑰 ,以後的傳輸數據都將被 加密。
- 客戶端使用客戶端私鑰解密 得到
- 客戶端計算 的 md5 值 , 為上一步得到的會話密鑰
- 客戶端將 發送給服務器
- 服務器計算 的 md5 值
- 服務器比較 和 ,兩者相同則認證成功
至此,服務器和客戶端認證通過,可以使用會話密鑰進行加密和解密傳輸
- 客戶端和服務器通過 進行會話數據安全傳輸
SSH 密鑰#
SSH 密鑰是 SSH 協議中使用的訪問憑據,類似於密碼。SSH 密鑰授予用戶自動遠程訪問企業的核心設備的權限。
主機密鑰 Host Key#
每個主機(即計算機)都有唯一的主機密鑰。
- 在 Linux 中存儲在
/etc/sshssh_host_<rsa/dsa/ecdsa/ed25519>_key
- 在 Windows 中存儲在
C:\ProgramData\ssh
當你首次通過 SSH 連接一台遠程主機時,通常會得到這樣的提示:
$ ssh user@ip-address
The authenticity of host 'ip-address (ip-address)' can't be established.
ECDSA key fingerprint is SHA256:hjn60Ix3hjduyfhjHLJKOdJSDDX6beXpfp0ypeqTOPQ+f0tU.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
當你輸入yes
並按下 Enter 繼續之後,你就會看到這樣提示:
Warning: Permanently added 'ip-address' (ECDSA) to the list of known hosts.
user@ip-address's password:
它就會以這樣的形式添加到已知主機密鑰列表中
ip-address ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEvRRBRoCJSuJuEaXK3i3k/4Cd+uriN5cKPGbbl/Q5f5DhjduyfhjHLQXDZPVDw0reLJKmIcGcZh2qQHX5qjMLQ=
已知主機密鑰列表: SSH 客戶端用來存儲曾經連接到的主機的主機密鑰
- 在 Linux 中存儲在
/etc/ssh/known\_hosts.ssh/known\_hosts
- 在 Windows 中存儲在
C:\Users\User\.ssh\known_host
授權密鑰 Authorized Key#
SSH 中的授權密鑰是用於授予用戶登錄訪問權限的公鑰。身份驗證機制稱為公鑰身份驗證。在 OpenSSH 中可以使用ssh-keygen
工具生成,通常會生成一對密鑰(私鑰 - 公鑰),如下圖所示。
用於服務器端的 authorized_keys 文件#
在 authorized_keys 文件為每個用戶單獨配置授權密鑰。
- 在 Linux 中存儲在
~/.ssh/authorized_keys
- 在 Windows 中存儲在
C:\Users\user\.ssh\authorized_keys
你可以在 SSH 服務器的配置文件中修改它的保存路徑
授權密鑰內容如下所示:
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBN+Mh3U/3We4VYtV1QmWUFIzFLTUeegl1Ao5/QGtCRGAZn8bxX9KlCrrWISIjSYAwCajIEGSPEZwPNMBoK8XD8Q= user@host-name
標識密鑰 Identity Key #
標識密鑰是一種私鑰,在 SSH 公鑰身份驗證中用於授予訪問服務器的權限。在 OpenSSH 中可以使用ssh-keygen
工具生成,通常會生成一對密鑰(私鑰 - 公鑰),如下圖所示。
會話密鑰 Session Key#
SSH 協議利用 Key Exchange 算法為每個會話或連接派生一個唯一的密鑰,這個密鑰被稱為會話密鑰 Session Key,常見的 Key Exchange 算法有 Diffie-Hellman 和 Elliptic-curve Diffie–Hellman。
會話密鑰在會話連接雙方之間共享,這很容易受到中間人攻擊。
向前保密性:由於使用了會話密鑰,即使長期密鑰(主機密鑰)洩露,入侵者也無法解密之前的會話內容。
關於密鑰的基礎知識#
公鑰 Public Key#
公鑰是與私鑰算法一起使用的密鑰對的非秘密一半。公鑰通常用於加密會話密鑰、驗證數字簽名,或加密可以用相應的私鑰解密的數據。公鑰和私鑰是通過一種算法得到的一个密鑰對 (即一個公鑰和一個私鑰),其中的一个向外界公開,稱為公鑰;另個自己保留,稱為私鑰。通過這種算法得到的密鑰對能保證在世界範圍內是唯一的。使用這個密鑰對的時候,如果用其中一個密鑰加密一段數據,必須用另一個密鑰解密。如用公鑰加密數據就必須用私鑰解密,如果用私鑰加密也必須用公鑰解密,否則解密將不會成功。
在 SSH 中,公鑰加密用於對計算機和用戶進行身份驗證。主機密鑰對主機進行身份驗證。授權密鑰和身份密鑰對用戶進行身份驗證。
私鑰 Private Key#
在公鑰密碼系統中,私鑰是用於對文檔進行數字簽名的密鑰。在某些密碼系統中,它還可用於解密使用公鑰加密的數據。每個私鑰都有一個對應的公鑰。通常,公鑰可以很容易地從私鑰派生,但從公鑰派生私鑰在計算上是不可行的。
在 SSH 中,私鑰用於對計算機和用戶進行身份驗證。主機密鑰對服務器進行身份驗證,標識密鑰用作用戶的身份驗證憑據。
SSH 配置文件#
OpenSSH 客戶端配置文件#
配置文件的保存位置:
- Linux
~/.ssh/config/etc/ssh/ssh_config
- Windows
C:\Users\user\.ssh\config
通常情況下配置文件是不存在的,你可以手動創建它
- Linux
touch ~/.ssh/config&&chmod 600 ~/.ssh/config
- Windows 到
C:\Users\user\.ssh\
路徑下手動創建文本文件並刪除.txt
後綴
配置文件的結構#
Host hostname1
SSH_OPTION value
SSH_OPTION value
Host hostname2
SSH_OPTION value
Host *
SSH_OPTION value
- config 的結構如上所示,是一塊一塊的。
- 縮進其實不是必須的,但是有縮進非常有助於查看。
- 每一塊使用 Host 指令開始,每一個 Host 塊可以針對一個或者多個需要匹配的內容(多個使用空格分隔),也可以採用下面這些特殊標識符:
*
匹配 0 或者任意個字符。比如Host *
匹配所有的 Hosts,192.168.0.*
匹配192.168.0.0/24
這個 subnet 下的 IP。?
匹配一個字符。如10.10.0.?
匹配10.10.0.[0-9]
。!
取反,即不匹配。比如Host 10.10.0.* !10.10.0.5
匹配10.10.0.0/24 subnet
但是10.10.0.5
除外。
匹配規則: SSH 客戶端是從上往下匹配的,因此如果有多個 Host 匹配命中,其中定義的配置參數第一個出現的生效,比如第一個匹配配置組裡面有 User 配置,最後匹配到的配置組裡面也有,那是第一個匹配到的 User 會被實際使用。所以建議將比較具體的匹配放在上方,通用的放在後面 (比如針對某一個 ip 段的放在上面,針對所有的放在最後面)。
配置文件詳解#
Host host-name
指定配置塊,必配項user username
指定登錄用戶,必配項hostname 10.0.0.1
指定服務器地址,通常用 ip 地址,必配項port 22
指定認證私鑰文件,必配項Identityfile ~/.ssh/id_rsa
指定本地認證私鑰地址IdentityFile ~/.ssh/id_rsa.pub
指定認證私鑰文件ForwardAgent yes
允許 ssh-agent 轉發ForwardX11 yes
允許許 X11 轉發 X11 轉發ForwardX11Trusted yes
遠程 X11 客戶端將具有對原始 X11 顯示器的完全訪問權限。DynamicForward 2000
指定通過安全通道轉發的本地端口RemoteForward 3000
指定遠程主機上的一個 TCP 端口通過安全通道轉發到本地主機上的指定主機和端口。第一個參數必須是:[bind_address:]port
,第二個參數必須是host:port
。SSH 隧道LocalForward
指定本地機器上的一個 TCP 端口通過安全通道轉發到遠程機器上的指定主機和端口。第一個參數必須是\[bind\_address:]port
,第二個參數必須是host:port
。ExitOnForwardFailure yes
當動態、隧道、本地和遠程端口轉發設置失敗時,是否應終止連接。ClearAllForwardings
指定清除在配置文件中或在命令行上指定的所有local
、remote
和dynamic
端口發。GatewayPorts 2001
指定是否允許遠程主機連接到本地的端口IdentitiesOnly no
指定 ssh 是否僅使用配置文件或命令行指定的私鑰文件進行認證。值為yes
或no
,默認為no
,該情況可在 ssh-agent 提供了太多的認證文件時使用。StrictHostKeyChecking ask
ask
:默認值,第一次連接陌生服務器時提示是否添加,同時如果遠程服務器公鑰改變時拒絕連接;yes
:不會自動添加服務器公鑰到~/.ssh/known_hosts
中,同時如果遠程服務器公鑰改變時拒絕連接;no
:自動增加新的主機鍵到~/.ssh/known_hosts
中。
BindAddress 10.0.0.1
指定使用本地計算機上的指定地址作為連接的源地址。Protoco- 2
按首選項順序指定協議版本。多個版本必須以逗號分隔。Cipher <char>
在 SSH v1 中設置加密用的密碼。Ciphers <char>
- 按首選項順序指定 SSH v2 允許的密碼。
- 多個密碼必須以逗號分隔。
- 命令
ssh -Q cipher
可用於查詢支持的密碼。
HostKeyAlgorithms ssh-ed25519
指定客戶端要使用的 SSH v2 的主機密鑰算法,按優先級排序。HostKeyAlias username
指定一個別名,當在密鑰數據庫文件中查找或保存主機鑰匙時,使用該別名而不是真實的主機名稱。GlobalKnownHostsFile <path>
#指定要用於全局主機密鑰數據庫的文件,而不是/etc/ssh/sh_known_hosts
。HashKnownHosts yes
將主機名和地址添加到~/.ssh/known_hosts
時應對其進行哈希處理。Compression no
指定是否使用壓縮。CompressionLeve- 1
指定在啟用壓縮時要使用的壓縮級別。EscapeChar ~
設置 escape 按鍵。ConnectionAttempts 10
指定退出前要進行的嘗試次數。ConnectTimeout 10
指定連接到 SSH 服務器時使用的超時(以秒為單位),而不是使用默認系統 TCP 超時。ControlMaster 3
允許通過單個網絡連接共享多個會話。ControlPath <path>
#指定用於連接共享的控制 socket 的路徑,或指定字符串none
以禁用連接共享。RhostsAuthentication no
設置是否使用基於 rhosts 的安全驗證。RhostsRSAAuthentication no
設置是否使用用 RSA 算法的基於 rhosts 的安全驗證。HostbasedAuthentication yes
指定是否使用用戶主目錄中的.rhosts
或.shosts
文件以及全局配置中的/etc/hosts.equiv
和/etc/shosts.equiv
,嘗試基於 rhosts 的認證與公鑰認證。RSAAuthentication yes
設置是否使用 RSA 算法進行安全驗證。PasswordAuthentication yes
設置是否使用口令驗證。FallBackToRsh no
設置如果用 ssh 連接出現錯誤是否自動使用 rsh。UseRsh no
設置是否在這台計算機上使用 rlogin/rsh。BatchMode no
如果設為yes
,passphrase/password(交互式輸入口令)的提示將被禁止。當不能交互式輸入口令的時候,這個選項對腳本文件和批處理任務十分有用。CheckHostIP yes
設置 ssh 是否查看連接到服務器的主機的 IP 地址以防止 DNS 欺騙。建議設置為yes
。StrictHostKeyChecking no
如果設置成yes
,ssh 就不會自動把計算機的密匙加入$HOME/.ssh/known_hosts
文件,並且一旦計算機的密匙發生了變化,就拒絕連接。KbdInteractiveAuthentication yes
指定是否使用鍵盤交互式身份驗證。這是密碼身份驗證、一次性密碼和多重身份驗證的常用方法。KbdInteractiveDevices
LocalCommand ipconfig
指定成功連接到服務器後要在本地計算機上執行的命令。LogLeve- ERROR
指定來自 ssh 的日誌信息的粗略程度。可以是 QUIET,FATAL,ERROR,INFO,VERBOSE,DEBUG,DEBUG1,DEBUG2,DEBUG3。Macs hmac-sha1
按優先順序指定 Mac(消息驗證碼)算法,命令ssh -Q mac
可以用來查詢支持的 Mac 算法。NoHostAuthenticationForLocalhost yes
如果主目錄是跨機器共享的,就可以使用這個選項。在這種情況下,localhost 將指的是每台機器上的不同機器,而用戶將得到許多關於改變主機密鑰的警告。PreferredAuthentications
指定客戶端應嘗試 SSH v2 身份驗證方法的順序。ProxyCommand
指定用於連接到服務器的命令。SSH 客戶端使用其標準輸入和標準輸出與代理命令進行通信,代理命令應將通信傳遞給 SSH 服務器。PubkeyAuthentication yes
指定是否使用 SSH 密鑰嘗試公鑰認證。SendEnv
指定應該向服務器發送哪些環境變量。ServerAliveCountMax 10
設置客戶端發送的keepalive
的數量,而客戶端沒有收到來自服務器的任何信息反饋。當達到這個閾值時,客戶端將終止會話。ServerAliveInterva- 5
指定向服務器發送keepalive
信息的時間間隔。這些信息是通過加密通道發送的,用於檢測服務器是否崩潰或網絡是否中斷。TCPKeepAlive yes
是否向對方發送 TCP keepalives。這是在 TCP 協議層面上的操作。Tunne- yes
請求在客戶端和服務器之間進行設備轉發。這用於通過 SSH 實現 VPNTunnelDevice remote_tun
要打開 tun 的設備,local_tun 或 remote_tunUsePrivilegedPort no
指定是否使用特權端口進行外發連接。UserKnownHostsFile <path>
指定一個文件,用戶的已知主機密鑰數據庫,而不是默認的~/.ssh/known_hosts
。VerifyHostKeyDNS yes
指定是否使用 DNS 和 SSHFP 資源記錄來驗證遠程密鑰。VisualHostKey yes
在登錄時或對於未知主機鑰匙,除了十六進制指紋字符串外,是否還打印遠程主機鑰匙指紋的 ASCII 藝術圖。
Open SSH 服務器端配置文件#
OpenSSH 服務器在啟動時讀取配置文件,通常配置文件的保存位置:
- Linux
/etc/ssh/sshd_config
- Windows
C:\ProgramData\ssh\sshd_config
配置文件的關係#
配置詳解#
- 關於 SSH Server 的整體設定,包含使用的 port 啦,以及使用的密碼演算方式
Port 22
SSH 默認使用 22 這個 portProtoco- 2,1
選擇的 SSH 協議版本,可以是 1 也可以是 2,如果要同時支持兩者,就必須要使用 2,1 這個分隔了ListenAddress 10.0.0.1
只監聽來自 10.0.0.1 的 SSH 聯機。(假設有兩個 IP 10.0.0.1 與 10.0.0.2 )PidFile /var/run/sshd.pid
可以放置 SSHD 這個 PID 的檔案,左列為默認值LoginGraceTime 600
連接等待時間(單位秒)Compression yes
是否可以使用壓縮指令
- 說明主機的 Private Key 放置的檔案,默認使用下面的檔案即可
HostKey /etc/ssh/ssh_host_key
SSH v1 使用的私鑰HostKey /etc/ssh/ssh_host_rsa_key
SSH v2 使用的 RSA 私鑰HostKey /etc/ssh/ssh_host_dsa_key
SSH v2 使用的 DSA 私鑰KeyRegenerationInterva- 3600
重新建立主機密鑰的時間間隔ServerKeyBits 768
Server key 的長度
- 關於登錄文件的訊息數據放置與 daemon 的名稱
SyslogFacility AUTH
當有人使用 SSH 登入系統的時候,SSH 會記錄信息在 daemon name 下,默認是以 AUTH 來設定的,即/var/log/secure
裡面,其它可用的 daemon name 為:DAEMON,USER,AUTH,LOCAL0,LOCAL1,LOCAL2,LOCAL3,LOCAL4,LOCAL5,LogLeve- INFO
登錄記錄的等級
- 登入設定部分
PermitRootLogin no
是否允許 root 登入。默認是允許的,但是建議設定成 noUserLogin no
在 SSH 底下本來就不接受 login 這個程序的登入StrictModes yes
使用者的 host key 改變之後,Server 就不接受新的 SSH 連接RSAAuthentication yes
是否完全使用 RSA 認證,僅針對 SSH v1PubkeyAuthentication yes
是否允許 Public Key 僅針對 SSH v2AuthorizedKeysFile .ssh/authorized_keys
密鑰身份認證的密鑰路徑
- 認證部分
RhostsAuthentication no
是否使用.rhosts
,因為不安全了,所以通常禁用IgnoreRhosts yes
是否取消使用~/.ssh/.rhosts
RhostsRSAAuthentication no
是否使用/etc/hosts.equiv
中的 rhosts 配合 RSA 演算方式來進行認證,僅針對 SSH v1HostbasedAuthentication no
這個項目與上面的項目類似,僅針對 SSH v2IgnoreUserKnownHosts no
是否忽略/home/.ssh/known_hosts
中記錄的主機內容PasswordAuthentication yes
是否開啟密碼驗證PermitEmptyPasswords no
是否允許以空的密碼登入ChallengeResponseAuthentication yes
挑戰任何的密碼認證,任何 login.conf 規定的認證方式,均可適用!PAMAuthenticationViaKbdInt yes
是否啟用其它的 PAM 模塊!啟用會導致 PasswordAuthentication 設定失效
- 與 Kerberos 有關的參數設定
KerberosAuthentication no
KerberosOrLocalPasswd yes
KerberosTicketCleanup yes
KerberosTgtPassing no
- 底下是有關在 X-Window 底下使用的相關設定
X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost yes
- 登入後的項目
PrintMotd no
登入後是否顯示出一些信息,例如上次登入的時間、地點等等,默認是 yesPrintLastLog yes
顯示上次登入的信息,默認是 yesKeepAlive yes
是否開啟 keepaliveUsePrivilegeSeparation yes
使用者的權限設定項目MaxStartups 10
同時允許尚未登入的聯機會話數量(連上 SSH 但是尚未輸入密碼時,即聯機會話)
- 關於拒絕連接的設定項目
DenyUsers test
設定拒絕登錄的用戶名稱DenyGroups test
設置拒絕登錄的用戶群組
- 關於 SFTP 服務的設定項目
Subsystem sftp /usr/lib/ssh/sftp-server
known_hosts#
known_hosts 中存儲是已認證的遠程主機 host key,每個 SSH Server 都有一個 secret, unique ID, called a host key。
known_hosts 的存儲路徑:
- Linux:
~/.ssh/known_hosts
- Windows:
C:\Users\uesr\.ssh\known_hosts
當我們第一次通過 SSH 登錄遠程主機的時候,Client 端會有如下提示:
Host key not found from the list of known hosts.
Are you sure you want to continue connecting (yes/no)?
此時,如果我們選擇 yes,那麼該 host key 就會被加入到 Client 的 known_hosts 中,格式如下:
# domain name+encryption algorithm+host key
example.hostname.com ssh-rsa AAAAB4NzaC1yc2EAAAABIwAAAQEA。。。
為什麼需要 known_hosts? 這個文件主要是通過 Client 和 Server 的雙向認證,從而避免 #中間人攻擊,每次 Client 向 Server 發起連接的時候,不僅僅 Server 要驗證 Client 的合法性,Client 同樣也需要驗證 Server 的身份,SSH client 就是通過 known_hosts 中的 host key 來驗證 Server 的身份的。
實用教程#
SSH 客戶端與服務器端安裝#
Linux 驗證安裝#
在大多數 Linux 系統中是默認安裝好了的,你可以實用下面的命令檢查。
- 成功顯示版本號,證明已安裝 OpenSSH
- 驗證服務時原點是綠色的,證明 SSH 服務正在運行
#驗證ssh版本
$ ssh -V
OpenSSH_8.2p1 Ubuntu-4ubuntu0.4, OpenSSL 1.1.1f 31 Mar 2020
#驗證SSH服務狀態
$ systemctl status sshd.service
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; ena>
Active: active (running) since Sun 2022-02-27 19:28:>
Docs: man:sshd(8)
man:sshd_config(5)
Process: 796 ExecStartPre=/usr/sbin/sshd -t (code=exi>
Main PID: 824 (sshd)
Tasks: 1 (limit: 4491)
Memory: 4.0M
CGroup: /system.slice/ssh.service
└─824 sshd: /usr/sbin/sshd -D [listener] 0 o>
مار 03 00:44:39 zac-ubuntu sshd[21852]: pam_unix(sshd:ses>
مار 03 00:44:39 zac-ubuntu sshd[21852]: pam_unix(sshd:ses>
مار 03 00:44:54 zac-ubuntu sshd[21917]: Accepted password>
مار 03 00:44:54 zac-ubuntu sshd[21917]: pam_unix(sshd:ses>
مار 03 00:45:02 zac-ubuntu sshd[21985]: Accepted password>
مار 03 00:45:02 zac-ubuntu sshd[21985]: pam_unix(sshd:ses>
مار 03 19:56:27 zac-ubuntu sshd[26728]: Accepted password>
مار 03 19:56:27 zac-ubuntu sshd[26728]: pam_unix(sshd:ses>
مار 03 21:28:46 zac-ubuntu sshd[28737]: Accepted password>
مار 03 21:28:46 zac-ubuntu sshd[28737]: pam_unix(sshd:ses>
lines 1-22/22 (END)
Linux 手動安裝 SSH#
安裝命令:
# arch
pacman -S openssh
# ubuntu
apt-get install openssh
# RHEL
yum install openssh
啟動服務:
# 啟動SSH守護進程
systemctl start sshd
# 開機自啟
systemctl enable sshd
Windows 手動安裝 SSH#
在 Window 10(版本 1809 及更高版本)開始支持 OpenSSH,若要安裝 OpenSSH 组件:
- 打開 “設置”,選擇 “應用”>“應用和功能”,然後選擇 “可選功能” 。
- 掃描列表,查看是否已安裝 OpenSSH 。 如果未安裝,請在頁面頂部選擇 “添加功能”,然後:
- 查找 “OpenSSH 客戶端”,再單擊 “安裝”
- 查找 “OpenSSH 服務器”,再單擊 “安裝” 設置完成後,回到 “應用”>“應用和功能” 和 “可選功能”,你應會看到已列出 OpenSSH 。
分步教程參考《Windows - 安裝 SSH 服務器》
對於 Window 10(版本 1809 以下)以及 Windows 7 手動安裝 OpenSSH
- 下載對用系統版本的安裝文件;GitHub 下載連接
- 將下載好的安裝
.zip
文件解压; - 將解藥好的文件夾整體複製到
C:/Program Files/
路徑下,當然你可以放到你電腦上的任何你喜歡的路徑下; - 在計算機(windows7) 或此電腦(windows10),右鍵 --> 屬性 --> 高級系統設置 --> 環境變量 -- 系統變量,在此框裡面找到
Path
進行編輯;
- windows7 系統編輯時是以文本形式,所以就需要在最後先添加 “;” 英文分號,再把你安裝路徑
C:\Program Files\OpenSSH-Win64
粘貼進去;windows 10 系統添加比較方便,進到 Path 裡面,點擊新建直接粘貼進去;
詳細教程請參考《Windows 安裝 OpenSSH 支持 SSH》
在 Windows 上驗證安裝,打開cmd
或者powershell
$ ssh -V
OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2
設置 SSH 服務開機自啟動
SSH 端口號#
默認狀態下,ssh 是工作在 tcp 22 端口。
在 SSH 的 C/S 模式中,SSH Server 會監聽 22 端口,SSH Client 會使用隨機端口號(1024~65535)與 SSH Server 建立連接。
如何更改 SSH Server 的默認端口#
找到 SSH 的配置文件:
- 在 Linux 中:
/etc/ssh/sshd_config
- 在 Windows 中:
C:\ProgramData\ssh\sshd_config
#Port 22
取消前面的註釋#
,將22
修改為你想 SSH 工作的端口(請不要與其他端口衝突)。
連接 SSH 時使用指定端口號#
ssh -p <port-number> user@ip-address
sftp -P <port-number> user@ip-address #注意P使用大寫字母
SFTP 使用 SSH 協議傳輸數據,所以共用端口號
密鑰生成工具ssh-keygen
#
ssh-keygen
是用於創建新的密鑰對的工具。即上面章節中提及的授權密鑰與標識密鑰組成的密鑰對。
以下是操作示例:
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa): #你可以在這一步中指定密鑰存儲的路徑
Enter passphrase (empty for no passphrase): #你可以在這一步指定一個密碼(passphrase)用于保護密鑰
Enter same passphrase again: #再次確認上一步的密碼(passphrase)
Your identification has been saved in /home/user/.ssh/id_rsa. #提示你的私鑰保存路徑
Your public key has been saved in /home/user/.ssh/id_rsa.pub. #提示你的公鑰保存路徑
The key fingerprint is: SHA256:Up6KjbnEV4Hgfo75YM393QdQsK3Z0aTNBz0DoirrW+c user@host
The key's random art image is:
+---[RSA 2048]----+
| . ..oo..|
| . . . . .o.X.|
| . . o. ..+ B|
| . o.o .+ ..|
| ..o.S o.. |
| . %o= . |
| @.B... . |
| o.=. o. . . .|
| .oo E. . .. |
+----[SHA256]-----+
host (11:40) ~>
上面所有的步驟都可以留空,不用填寫任何內容
選擇算法和密鑰大小#
在上面的 “The key's random art image is:” 下的圖中我們可以看到RSA 2048
,RSA
就是密鑰算法;2048
就是密鑰大小。
ssh-keygen -t <arithmetic> -b <size> #-t後面指定算法名;-b後面指定密鑰大小
SSH 支持多種密鑰算法:
rsa
是最早的公鑰密碼系統之一,被廣泛用於安全數據傳輸。它的安全性取決於整數分解,因此永遠不需要安全的 RNG(隨機數生成器)。與 DSA 相比,RSA 的簽名驗證速度更快,但生成速度較慢。建議密鑰大小至少為 2048 位。4096 位更好。dsa
一種舊的美國政府數字簽名算法。它基於計算離散對數的難度,與 RSA 相比,DSA 的簽名生成速度更快,但驗證速度較慢。通常密鑰大小 1024。ecdsa
是 DSA(數字簽名算法)的椭圆曲线實現。椭圆曲线密碼術能夠以較小的密鑰提供與 RSA 相對相同的安全級別。它還具有 DSA 對不良 RNG 敏感的缺點。支持三種密鑰大小:256、384 和 521 位,建議 521 位。ed25519
是 EdDSA 簽名方案,但使用 SHA-512/256 和 Curve25519;它是一條安全的椭圆形曲線,比 DSA,ECDSA 和 EdDSA 提供更好的安全性,並且具有更好的性能。這是 OpenSSH 中添加的新算法,僅少量的客戶端支持。
- 根據數學特性,這四種類型又可以分為兩大類,dsa/rsa 是一類,ecdsa/ed25519 是一類,後者算法更先進。
- dsa 因為安全問題,已不再使用了。
- ecdsa 因為政治原因和技術原因,也不推薦使用。
- rsa 是目前兼容性最好的,應用最廣泛的 key 類型,在用 ssh-keygen 工具生成 key 的時候,默認使用的也是這種類型。不過在生成 key 時,如果指定的 key size 太小的話,也是有安全問題的,推薦 key size 是 3072 或更大。
- ed25519 是目前最安全、加解密速度最快的 key 類型,由於其數學特性,它的 key 的長度比 rsa 小很多,優先推薦使用。它目前唯一的問題就是兼容性,即在舊版本的 ssh 工具集中可能無法使用。不過據我目前測試,還沒有發現此類問題。 -- 摘自《RSA,DSA,ECDSA,EdDSA 和 Ed25519 的區別》
使用ssh-keygen
創建主機密鑰#
該工具還用於創建主機密鑰。主機密鑰只是普通的 SSH 密鑰對。對於上面提到的四種算法,每台主機都可以根據這四種算法各生成一對密鑰。在 Linux 中示例如下:
- /etc/ssh/ssh_host_dsa_key
- /etc/ssh/ssh_host_dsa_key.pub
- /etc/ssh/ssh_host_ecdsa_key
- /etc/ssh/ssh_host_ecdsa_key.pub
- /etc/ssh/ssh_host_ed25519_key
- /etc/ssh/ssh_host_ed25519_key.pub
- /etc/ssh/ssh_host_rsa_key
- /etc/ssh/ssh_host_rsa_key.pub
主機密鑰通常在安裝 SSH 服務時自動生成。它們也可以隨時再生,如果主機密鑰發生更改,客戶端可能會發出有關已更改密鑰的警告。
將密鑰複製到服務器的工具ssh-copy-id
#
除了手動將客戶端id-rsa.pub
中的授權密鑰複製到服務器端的 authorized_keys 內以外,你還可以使用ssh-copy-id
工具在命令行中完成此操作。
首先確認你已經在客戶端生成了一對密鑰(公鑰 - 密鑰),下面是複製命令:
ssh-copy-id -i <pub_key path> user@serverhost #<pub_key path>:公鑰的文件路徑
執行成功後客戶端的授權密鑰就出現在了服務器端的 authorized_keys 內
在 Windows 上是沒有
ssh-copy-id
命令的,你可以參考《windows 無法使用 ssh-copy-id 解決辦法》。
實現 SSH 免密碼登錄(公鑰身份認證)#
準備條件#
- 安裝好 SSH 客戶端與服務器端
簡單配置服務器端#
- 為你要登錄的用戶 user 創建
~/.ssh
目錄以及~/.ssh/authorized_keys
文件。並設置正確的權限(否則 SSH 會拒絕連接):
# 確認當前用戶為harttle
whoami
# 創建.ssh目錄
mkdir ~/.ssh
chmod 700 ~/.ssh
# 創建對方公鑰文件
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
以上命令適用於 Linux,在 Windows 上找到
C:\Users\user\.ssh\
目錄,通常authorized_keys
文件會自動生成,如果沒有可以手動創建一個文本文件並將名稱改為authorized_keys
(注意:不能有.txt
或其他後綴)。
- 將客戶端生成的公鑰(授權密鑰)
~/.ssh/id_rsa.pub
中的內容複製到服務器端的~/.ssh/authorized_keys
文件中。
cat ~/.ssh/id_rsa.pub | ssh user 'cat >> .ssh/authorized_keys'
在 Linux 上你也可以使用
ssh-copy-id
工具來複製密鑰;
現在你就可以通過以下命令實現免認證登錄了
ssh <user>@<ipaddress>
在以 Windows 為服務器端時可能無法配置成功,參考 7.4 Windows 配置自動登錄的問題
SSH 身份認證代理ssh agent
#
ssh-agent
是一種控制用來保存公鑰身份驗證所使用的私鑰的程序。
本質上ssh-agent
就是一個密鑰管理器,運行ssh-agent
以後,使用 ssh-add 將私鑰交給ssh-agent
保管,其他程序需要身份驗證的時候可以將驗證申請交給ssh-agent
來完成整個認證過程。
ssh agent
的使用場景#
-
使用不同的密鑰連接到不同的主機時,需要手動指定對應的密鑰。ssh-agent 可以幫助我們選擇對應的密鑰進行認證,不用手動指定密鑰即可進行連接。
如果我們在使用
ssh-keygen
生成密鑰對時沒有使用默認名稱 id_rsa 作为密鑰名稱,而是使用其他名稱,比如 is_rsa_test 作为密鑰名稱,那麼當我們使用該密鑰對遠程連接服務器ssh user@host
依然會提示輸入服務器 host 的密碼。因為 ssh 基於密鑰進行認證時,默認會使用
~/.ssh/id_rsa
進行認證,當你使用非默認名稱的私鑰進行認證時,需要手動指明對應的私鑰,如果不指明對應的私鑰,ssh 仍然會默認使用~/.ssh/id_rsa
進行認證,所以無法認證成功。雖然可以通過
-i
選項指定對應的私鑰文件進行認證,ssh -i ~/.ssh/id_rsa_test user@host
,但是如果有很多密鑰對,使用起來就過於繁瑣。而ssh-agent
則可以幫我們管理這些密鑰,避免手動指定密鑰,ssh-agent
會幫助我們選擇對應的密鑰。使用ssh-add ~/.ssh/id_rsa_test
將密鑰加入到ssh-agent
中。 -
當私鑰設置了密碼,我們又需要頻繁的使用私鑰進行認證時,ssh-agent 可以幫助我們免去重複的輸入密碼的操作。
如果生成密鑰對,同時指定私鑰的密碼,每次使用私鑰進行認證連接是,都会要求輸入私鑰密碼,如果你在當前 ssh 會話中需要反復的連接到服務器,那麼反復的輸入複雜的私鑰密碼,的確會比較麻煩,ssh-agent 可以幫助我們,在一個 ssh 會話中,只要輸入一次私鑰密碼,在同一 ssh 會話中之後再次使用到相同的私鑰時,即可不用再次輸入對應密碼。
如何使用ssh agent
#
-
開啟
ssh-agent
進程進入 ssh-agent 環境:
#在Linux上 ssh-agent bash ssh-agent $SHELL eval $(ssh-agent) #在Windows ssh-agent #在Windows上也可以到服務裡面手動啟動OpenSSH Authentication Agent服務
此時會發現系統多增加了一個 ssh-agent 進程
ssh-agent
參數參數 描述 -a <bind_address> 將代理綁定到 Unix 域套接字綁定地址 -d 調試模式 -D 前台模式。 -k 把 ssh-agent 進程殺掉(在 Windows 上無效) -s 生成 Bourne shell 風格的命令輸出 -E <fingerprint_hash> 指定顯示密鑰指紋時使用的哈希算法。md5 或 sha256(默認值) -
將密鑰添加到
ssh-agent
中ssh-add <options> <path> #<path>密鑰的路徑
ssh-add
參數參數 描述 -l 列出當前 agent
中所有的密鑰指紋-L 列出當前 agent
中所有的公鑰參數-E <fingerprint_hash> 指定顯示密鑰指紋時使用的哈希算法。md5 或 sha256(默認值) -k 添加密鑰到 agent
或從agent
中移除密鑰時跳過證書-K 從 FIDO 身份驗證器加載駐留密鑰 -c 使用添加的密鑰進行身份認證之前需經過確認 -t 添加密鑰時設置生存週期(單位:秒,可以在 sshd_config
中添加TIME FORMATS h
來更改時間單位,支持 s m h d w)-T 通過對每個私鑰執行簽名和驗證操作來測試與指定的私鑰是否可用 -d 從 agent
中刪除密鑰-D 從 agent
中刪除全部密鑰-x 使用密碼鎖定 agent
,即暫停agent
管理密鑰-X 使用密碼解鎖 agent
-q 操作成功後保持靜默 -h 添加密鑰時只用於特定主機或特定目標 -H 指定一個 hosts 文件用於此密鑰在身份認證時查找主機密鑰。可以多次指定多個 hosts 文件,用 ,
隔開
其他設置#
簡化登錄#
已經配置了免密碼登錄(公鑰身份認證),但是如果你的用戶名很複雜(例如用戶名是郵箱地址等),或者不想及服務器的 IP 地址,那麼可以更改配置文件來簡化流程。
找到配置文件的路徑:
- Linux
~/.ssh/config
- Windows
C:\Users\Lin\.ssh\config
添加下面的內容到config
文件中
Host <name> #自定義的名稱
HostName <ipaddress> #服務器端主機名稱或IP地址
UserName <user> #登錄時使用的用戶名
現在你就可以使用簡化的命令了
ssh <name>
你還可以參考客戶端配置文件詳解來添加你需要的功能。
安全文件傳輸工具#
安全文件傳輸 SFTP#
sftp 是一個文件傳輸程序,類似於 ftp,它使用 ssh 加密執行所有操作。它還可以使用 ssh 的公鑰身份驗證和壓縮功能。 可以
-
連接命令
sftp user@host:path #URI格式為 sftp://user@host:port/path
sftp
命令參數參數 描述 -a 嘗試繼續中斷的傳輸,而不是覆蓋文件的現有部分 -b 批處理模式 -B <buffer_size> 指定傳輸文件時使用的緩存大小。較大的緩存需要較少的往返行程,但內存消耗較高。默認值為 32768 字節 -l 限制帶寬,以 Kbit/s 為單位指定 -P 指定要連接的遠程主機上的端口 -p 保留原始的文件的修改時間、訪問時間和模式等 -4 與 ssh 命令相同 -6 與 ssh 命令相同 -A 與 ssh 命令相同 -C 與 ssh 命令相同 -F 與 ssh 命令相同 -i 與 ssh 命令相