因為我的伺服器集羣需要回收日誌到中央進行統一處理,所以需要建立ssh互信關係實現免密登錄。關於ssh的使用大家可能都很熟悉了,我們今天主要來講下ssh連接和免密登錄的原理。

scp 傳輸文件

scp(secure copy)linux系統下基於ssh登錄進行安全的遠程文件拷貝的命令。

# 傳遞文件到遠程
scp local_file remote_username@remote_ip:remote_file
# 傳遞文件夾到遠程
scp -r local_folder remote_username@remote_ip:remote_folder
# 複製遠程文件到本地,只是調換下文件參數位置即可
scp remote_username@remote_ip:remote_file local_file

遠程拷貝的命令還有rsyncscp消耗資源少,不會提高多少系統負荷,在這一點上,rsync就遠遠不及它了。rsyncscp會快一點,但當小文件多的情況下,rsync會導致硬碟I/O非常高,而scp基本不影響系統正常使用。

scp相似的命令是cp,但是cp只能本機拷貝而不能跨伺服器,因此需要與ssh合作構成scp命令。

我們直接使用scp來跨機器拷貝文件,會提示輸入密碼:

# 提示輸入server端伺服器的work用戶密碼
[[email protected] ~]$ scp test.php [email protected]:/home/work
[email protected] password:

原因就在於,scp是先使用ssh連接服務端機器後,再使用網路來執行遠程拷貝(cp)

可以參考ssh的過程:

# 同樣的提示輸入server端伺服器的work用戶密碼
[[email protected] ~]$ ssh [email protected]
[email protected] password:

ssh 加密信息

Secure Shell(安全外殼協議,簡稱SSH)是一種加密的網路傳輸協議,可在不安全的網路中為網路服務提供安全的傳輸環境。SSH通過在網路中創建安全隧道來實現SSH客戶端與伺服器之間的連接。雖然任何網路服務都可以通過SSH實現安全傳輸,SSH最常見的用途是遠程登錄系統,人們通常利用SSH來傳輸命令行界面和遠程執行命令。

SSHTelnet/rlogin等非安全shell的替代品,這些協議採用明文傳輸,會引入許多的安全性問題:

如圖所示,telnet使用23號埠,所有的信息,包括用戶名和密碼都是明文傳輸;而ssh使用22號埠,所有的信息都會被加密傳輸,安全性得到了很大的提高。

ssh使用十分簡單,選擇以什麼用戶連接哪臺機器,然後輸入密碼即可:

$ssh user@hostname
user@hostnames password:

對稱加密和非對稱加密

ssh的主要有點就是安全性,安全性依賴於加密方式,現在主要的加密方式有兩種:對稱加密和非對稱加密。

對稱加密

對稱加密使用同一個密鑰來進行加密和解密,這樣在傳輸時是安全可靠的,但是如何安全的保存密鑰呢,在集羣中,客戶端的數量巨大,一旦任意一個客戶端的密鑰被竊取,那麼整個系統的安全性也不復存在。

非對稱加密

由於對稱加密的這個弊端,產生了非對稱加密,非對稱加密中有兩個密鑰:公鑰和私鑰。公鑰由私鑰產生,但卻無法推算出私鑰;公鑰加密後的密文,只能通過對應的私鑰來解密。

非對稱加密的登錄流程:

初始狀態:topgun終端要登錄Server伺服器,發起連接請求ssh [email protected]

  1. 服務端運行有ssh服務,並持續監聽22號埠,因此可以生成一對公鑰和私鑰;此時將公鑰返回給客戶端
  2. 客戶端使用公鑰,對登錄密碼進行加密,(如伺服器work用戶密碼為xxx),生成公鑰加密字元串
  3. 客戶端將公鑰加密字元串發送給服務端
  4. 服務端使用私鑰,解密公鑰加密字元串,得到原始密碼
  5. 校驗密碼是否合法(此為本機work密碼)
  6. 返回登錄結果給客戶端:成功登錄或密碼錯誤

在非對稱加密中,由於只有公鑰會被傳輸,而私鑰是服務端本地保存,因此即便公鑰被監聽,也無法拿到原始密碼,從而登錄伺服器。

中間人攻擊

在非對稱加密中可以有效保護登錄密碼不被泄漏,但這是在建立連接到真實伺服器的情況下。設想一下,如果供給者並不監聽密碼或公鑰,而是直接偽裝成伺服器呢:

在該示例圖中,存在Hacker伺服器劫持了你的ssh建連請求(如通過DNS劫持等方式),導致你與Hacker機器的連接一切正常,因此它能拿到你的明文密碼,並通過明文密碼來攻擊真實的服務端。

那麼SSH採用了非對稱的加密方式,是怎麼解決這個問題的呢?

[[email protected]: ~]$ ssh [email protected]
The authenticity of host server.com (10.10.10.24) cant be established.
RSA key fingerprint is ad:2e:92:41:6f:31:b1:c1:35:43:eb:df:f1:18:a1:c1.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added server.com,10.10.10.24 (RSA) to the list of known hosts.
Password: (enter password)

在這個認證信息中,可以看到提示:無法確認主機server.com (10.10.10.24)的真實性,不過知道它的公鑰指紋,是否繼續連接?

輸入yes繼續連接後,就會確認該伺服器為可信任伺服器,然後添加到known_hosts文件中,下次不用再次確認,然後跳轉到輸入密碼的驗證階段。這種簡單粗暴的方式相當於讓我們肉眼比對來判斷目標伺服器是否是真實伺服器,我覺得並不是最理想的方式,希望後續會有更完美的認證方式。

之所以用fingerprint(公鑰指紋)代替key,主要是key過於長(RSA演算法生成的公鑰有1024位),很難直接比較。所以,對公鑰進行hash生成一個128位的指紋,這樣就方便比較了。

SSH免密登錄

我們已經掌握如何使用ssh登錄遠程伺服器了,但是每次登錄都要輸入密碼,比較麻煩。ssh提供一種免密登錄的方式:公鑰登錄。

  1. 在客戶端使用ssh-keygen生成一對密鑰:公鑰+私鑰
  2. 將客戶端公鑰追加到服務端的authorized_key文件中,完成公鑰認證操作
  3. 認證完成後,客戶端向服務端發起登錄請求,並傳遞公鑰到服務端
  4. 服務端檢索authorized_key文件,確認該公鑰是否存在
  5. 如果存在該公鑰,則生成隨機數R,並用公鑰來進行加密,生成公鑰加密字元串pubKey(R)
  6. 將公鑰加密字元串傳遞給客戶端
  7. 客戶端使用私鑰解密公鑰加密字元串,得到R
  8. 服務端和客戶端通信時會產生一個會話ID(sessionKey),用MD5R和SessionKey進行加密,生成摘要(即MD5加密字元串)
  9. 客戶端將生成的MD5加密字元串傳給服務端
  10. 服務端同樣生成MD5(R,SessionKey)加密字元串
  11. 如果客戶端傳來的加密字元串等於服務端自身生成的加密字元串,則認證成功
  12. 此時不用輸入密碼,即完成建連,可以開始遠程執行shell命令了

實現免密登錄

ssh-genkey是生成密鑰的工具,執行完成後生成公鑰和密鑰,這兩個文件會默認保存在~/.ssh/路徑下。常用的參數為:

  • -t: 指定生成密鑰類型(rsa、dsa)。默認為rsa
  • -f: 指定存放私鑰的文件,公鑰文件名為私鑰文件名加.pub後綴。默認為id_rsa
  • -P: 指定passphrase(私鑰的密碼),用於確保私鑰的安全。默認為空
  • -C: 備註。默認為user@hostname

我們直接執行來生成密鑰,所有的參數都可以為空,也就是一直回車確認:

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/work/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in id_rsa.
Your public key has been saved in id_rsa.pub.
The key fingerprint is:
74:17:74:38:b2:c7:70:fd:1d:33:eb:e2:71:71:cc:11 [email protected]

此時,生成的文件在~/.ssh/目錄下,我們會看到這些文件:

id_rsa // 私鑰文件
id_rsa.pub // 公鑰文件
authorized_keys // 存放客戶端公鑰的文件
known_hosts // 確認過公鑰指紋的可信伺服器列表的文件
config // 指定不同域名使用哪個密鑰的配置文件

因為一臺機器即能是客戶端,又能是服務端,因此同時存在authorized_keys(在該機器為服務端時使用)和Known_hosts(在該機器為客戶端時使用)。

我們的伺服器會有很多的用戶,如果所有的用戶都用同一份密鑰,可能就沒辦法劃分許可權或者區分用戶,如多個用戶提交git就需要按照用戶名來生成密鑰,用於區分用戶。同時你可能也希望針對不同的伺服器使用不同的密鑰對,因此需要config配置文件來配置針對不同伺服器的配置:

$vim ~/.ssh/config
Host a.baidu.com
User work
IdentityFile ~/.ssh/id_rsa

Host b.baidu.com
User zhaoshuaiqiang
IdentityFile ~/.ssh/zhaoshuaiqiang

這樣在連接不同的伺服器時,就會使用不同的密鑰文件來登錄。

在客戶端生成密鑰對之後,將公鑰追加到伺服器的authorized_keys文件中即可。

...
15 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAn30bjwtkLW82vTlLMQnI/a42J2g7o+HBCpSzBgNG+xfZuSNQOAU8+FNKQvriT4AL7ToiTtrZDLOEGqyQzaxQejuNnWG6aQ9ETh96qXhVLecWidaBieFGuv+F
uXz6x551xtFXx64AzG+706dhnv1nOACYlrnfvXhi5kZzWzprET+CxMIeYhJQwwc19pF5zCWeU9QUvd1mOu0n8JVycevmuXRdVx9WpXq2+aaaaaaaa3uYGMBxvSLtT40O1AiEZ+k9EeYCnTEV
tnGoVWCyxpwv6rR/GDOtJL/d+/Wb6I0HEKxxe087yZz8GWpQN5TEIAjq3oEjI/aiGw== [email protected]
16 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzRmK+CAVLnryXqQwweu8Yji8bGAvqzf8PSDzYn1nmE6ZeDkBbrWvFlVZ2yOip3IX8RjvuPc28mTCr0LsIOOmpvET0SzOkt0hzLBPiyCN/QvbKU/RbUv8v5y2
hEAlbUkMEzv7qOHQEruGEvA5y99gf/nYjK5OFKVpmg838OScUV3i88Xbqk8rtcuRZHWuZLnuB5spBsEE5r1UrnH/Ik7frZr8Vb4X6aZWbAp1yc0SqZ8JXVbmOiakqq0WqkLm+zqhEwr+Ooh2guH23x9zjMqY
Uy+aaaaaBEBC+LepCvskArBt/SRwJDJkcItz8T7kBC3CP0Y0X4hB+6k6/yM/pup5w== [email protected]

此時,即可免密登錄伺服器。

私鑰的安全性

假設你已經實現了伺服器集羣的免密登錄,那麼如果你的一臺客戶端被攻擊成功了,那麼整個集羣的安全性便蕩然無存了。因此,我們有時還需要對密鑰做安全性保障,即設置私鑰密碼:

// 使用rsa方法加密,生成test密鑰對,私鑰密碼為123456
ssh-keygen -t rsa -f test -P 123456

此時,各機器仍然是免密登錄,但是需要你輸入私鑰密碼:

$ssh [email protected]
Enter passphrase for key /home/work/.ssh/test:

參考資料

  1. RUNOOB-Linux scp命令:runoob.com/linux/linux-
  2. linux-doc scp跨機遠程拷貝:linuxtools-rst.readthedocs.io
  3. 維基百科 Secure Shell:zh.wikipedia.org/wiki/S
  4. 簡書 圖解SSH原理:jianshu.com/p/33461b619
  5. CSDN scp在linux中實現兩臺主機傳件--互信無需輸入密碼: blog.csdn.net/posonrick

推薦閱讀:

相關文章