SSH,SSH-Key及其在Git中的使用

0 ssh是什麼

簡單說,SSH(Security Shell)是一個允許兩臺電腦之間通過安全的連接進行數據交換 的網絡協議。通過加密保證了數據的保密性和完整性。SSH 採用公鑰加密技術 來驗證遠程主機,以及(必要時)允許遠程主機驗證用戶。

如果一個用戶從本地計算機,使用SSH協議登錄另一臺遠程計算機,我們就可以認爲,這種登錄是安全的,即使被中途截獲,密碼也不會泄露。

最早的時候,互聯網通信都是明文通信,一旦被截獲,內容就暴露無疑。傳統的 FTP、Telnet 是再網絡中明文傳送數據、用戶帳號和密碼,很容易受到中間人攻擊 。1995年,芬蘭學者Tatu Ylonen設計了SSH協議,將登錄信息全部加密,成爲互聯網安全的一個基本解決方案,迅速在全世界獲得推廣,目前已經成爲Linux系統的標準配置。

需要指出的是,SSH只是一種協議,存在多種實現,既有商業實現,也有開源實現。本文針對的實現是OpenSSH(OpenBSD Secure Shell) ,它是自由軟件,應用非常廣泛。

2 中間人攻擊

SSH之所以能夠保證安全,原因在於它採用了公鑰加密。

整個過程是這樣的:
(1)遠程主機收到用戶的登錄請求,把自己的公鑰發給用戶。
(2)用戶使用這個公鑰,將登錄密碼加密後,發送回來。
(3)遠程主機用自己的私鑰,解密登錄密碼,如果密碼正確,就同意用戶登錄。

這個過程本身是安全的,但是實施的時候存在一個風險:如果有人截獲了登錄請求,然後冒充遠程主機,將僞造的公鑰發給用戶,那麼用戶很難辨別真僞。因爲不像https協議,SSH協議的公鑰是沒有證書中心(CA)公證的,也就是說,都是自己簽發的。

可以設想,如果攻擊者插在用戶與遠程主機之間(比如在公共的wifi區域),用僞造的公鑰,獲取用戶的登錄密碼。再用這個密碼登錄遠程主機,那麼SSH的安全機制就蕩然無存了。這種風險就是著名的"中間人攻擊"(Man-in-the-middle attack)。

SSH協議是如何應對的呢?

3 ssh提供的兩種登錄方式

3.1 口令登錄

如果你是第一次登錄對方主機,系統會出現下面的提示:

  $ ssh user@host

  The authenticity of host 'host (12.18.429.21)' can't be established.

  RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d.

  Are you sure you want to continue connecting (yes/no)?

這段話的意思是,無法確認host主機的真實性,只知道它的公鑰指紋,問你還想繼續連接嗎?

我們使用git工具,第一次與遠程託管平臺連接時往往就會有這個提示。另外我們在使用SSH遠程登錄工具如xshell時,也會有類似的提示。
在這裏插入圖片描述

所謂"公鑰指紋",是指公鑰長度較長(這裏採用RSA算法,長達1024位),很難比對,所以對其進行MD5計算,將它變成一個128位的指紋。上例中是98:2e:d7:e0🇩🇪9f:ac:67:28:c2:42:2d:37:16:58:4d,再進行比較,就容易多了。

很自然的一個問題就是,用戶怎麼知道遠程主機的公鑰指紋應該是多少?回答是沒有好辦法,遠程主機必須在自己的網站上貼出公鑰指紋,以便用戶自行覈對。

假定經過風險衡量以後,用戶決定接受這個遠程主機的公鑰。

  Are you sure you want to continue connecting (yes/no)? yes

系統會出現一句提示,表示host主機已經得到認可。

  Warning: Permanently added 'host,12.18.429.21' (RSA) to the list of known hosts.

然後,會要求輸入密碼。

  Password: (enter password)

如果密碼正確,就可以登錄了。

當遠程主機的公鑰被接受以後,它就會被保存在文件$HOME/.ssh/known_hosts之中。下次再連接這臺主機,系統就會認出它的公鑰已經保存在本地了,從而跳過警告部分,直接提示輸入密碼。

每個SSH用戶都有自己的known_hosts文件,此外系統也有一個這樣的文件,通常是/etc/ssh/ssh_known_hosts,保存一些對所有用戶都可信賴的遠程主機的公鑰。

3.2 公鑰登錄

使用密碼登錄,每次都必須輸入密碼,非常麻煩。好在SSH還提供了公鑰登錄,可以省去輸入密碼的步驟。

所謂"公鑰登錄",原理很簡單,就是用戶將自己的公鑰儲存在遠程主機上。登錄的時候,遠程主機會向用戶發送一段隨機字符串,用戶用自己的私鑰加密後,再發回來。遠程主機用事先儲存的公鑰進行解密,如果成功,就證明用戶是可信的,直接允許登錄shell,不再要求密碼。

這種方法要求用戶必須提供自己的公鑰。如果沒有現成的,可以直接用ssh-keygen生成一個:

  $ ssh-keygen

常用的選項
-b:指定密鑰長度;
-C:添加註釋;用於爲指定註釋,可以是任何內容,通常使用自己的郵件名作爲註釋。
-f:指定用來保存密鑰的文件名;
-t:指定要創建的密鑰類型(加密方式)。
-e:讀取openssh的私鑰或者公鑰文件;
-i:讀取未加密的ssh-v2兼容的私鑰/公鑰文件,然後在標準輸出設備上顯示openssh兼容的私鑰/公鑰;
-l:顯示公鑰文件的指紋數據;
-N:提供一個新密語;
-P:提供(舊)密語;
-q:靜默模式;

運行上面的命令以後,系統會出現一系列提示,可以一路回車。其中有一個問題是,要不要對私鑰設置口令(passphrase),如果擔心私鑰的安全,這裏可以設置一個。一般不設置,記不住【之後 還可更改此密碼,使用ssh-keygen -p】。
其中-t指定了加密方式,常用的兩者加密方式爲RSA 和ed25519。爲了安全考慮如果使用 RSA 加密方式則指定密鑰長度爲 -b 4096(1024 的密鑰長度能 夠被破解,建議指定爲 4096)。
但現在有了更安全的加密方式 ed25519 ,這是目前最受推薦的公鑰算法。當使用 ed25519 加密方式時,它會忽略 -b 選項,因爲它的長度是固定的。生成的密鑰更緊湊 、更短(僅包含 68 個字符)、在簽名驗證時也更快並且還更安全。它還將使用新的 OpenSSH 格式(OpenSSH 6.5+)而不是 PEM 格式保存私鑰,Windows10 中的 OpenSSH 最 先支持的也是 ed25519 類型的密鑰。
使用 rsa 加密方式的示例:

[fan 16:10:57]~$ ssh-keygen -t rsa -C "[email protected]" -b 4096
Generating public/private rsa key pair.
# 指定密鑰文件名稱;直接回車則使用默認名稱 id_rsa
Enter file in which to save the key (/home/fan/.ssh/id_rsa): /home/fan/.ssh/FDGitHub_rsa
# 輸入密碼(一般不輸入密碼,直接回車)
Enter passphrase (empty for no passphrase):
# 再次輸入密碼
Enter same passphrase again:
Your identification has been saved in /home/fan/.ssh/FDGitHub_rsa.
Your public key has been saved in /home/fan/.ssh/FDGitHub_rsa.pub.
The key fingerprint is:
SHA256:GcK7ORvFzH6fzA7qPmnzBr1DOWho5cCVgIpLkh6VGb8 [email protected]
The key's randomart image is:
+---[RSA 4096]----+
|   .+... .       |
|   +o.  o        |
| o.. oo..        |
|+o.   +*.o       |
|+..  E.=So .     |
|..    o== =      |
|     .=..+oo     |
|       +=o+= .   |
|      .++=.o*    |
+----[SHA256]-----+

# 查看公鑰文件中的內容
$ cat ~/.ssh/FDGitHub_rsa.pub
ssh-rsa "公鑰內容" [email protected]

# 注意在其他地方導入公鑰時一定要將公鑰文件中的 *全部內容* 都導入,包括末尾你的郵箱。

使用 ed25519 加密方式生成密鑰的示例:

ssh-keygen -t ed25519 -C "[email protected]"

# 默認的密鑰文件中將帶有ed25519,比如:
~/.ssh/id_ed25519
~/.ssh/id_ed25519.pub

公鑰是一串很長的字符;爲了便於肉眼比對和識別,所以有了指紋這東西;指紋位數短 ,更便於識別且與公鑰一一對應。
公鑰加密指紋 fingerprint 有兩種形式:
之前的十六進制形式:16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48
現在使用 sha256 哈希值並且使用 base64 進行格式 :SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8
指紋的用處之一是在使用 SSH 第一次連接到某主機時,會返回該主機使用的公鑰的指紋讓 你識別。

公鑰用於給別人用來加密文件。公鑰就是一把鎖,你把鎖給別人,他用鎖鎖住東西后,除 了你自己外其他人是沒有鑰匙(私鑰)的,都無法打開。配對的私鑰就是鑰匙。
必須保證使用你的公鑰的人明確知道這個公鑰一定是你的。你可以在網站或通過其它方式 公佈你的公鑰,以便他人進行對照確認。由於公鑰很長,所以有了對應的指紋(指紋更易 辨別,位數更少),可以通過指紋進行對照(公佈指紋)。

運行結束以後,在$HOME/.ssh/目錄下,會新生成兩個文件:id_rsa.pub和id_rsa。前者是你的公鑰,後者是你的私鑰。

這時再輸入下面的命令,將公鑰傳送到遠程主機host上面:

  $ ssh-copy-id user@host

好了,從此你再登錄,就不需要輸入密碼了。

如果還是不行,就打開遠程主機的/etc/ssh/sshd_config這個文件,檢查下面幾行前面"#"註釋是否取掉。

  RSAAuthentication yes
  PubkeyAuthentication yes
  AuthorizedKeysFile .ssh/authorized_keys

然後,重啓遠程主機的ssh服務。

  // ubuntu系統
  service ssh restart

  // debian系統
  /etc/init.d/ssh restart

通過上面的解釋可以知道,我們常用的xshell使用的是口令登錄,而我們的git工具使用的是祕鑰登錄,需要向遠程託管平臺提供自己的公鑰。

4 ssh基本用法

SSH主要用於遠程登錄。假定你要以用戶名user,登錄遠程主機host,只要一條簡單命令就可以了。

  $ ssh user@host

如果本地用戶名與遠程用戶名一致,登錄時可以省略用戶名。

  $ ssh host

SSH的默認端口是22,也就是說,你的登錄請求會送進遠程主機的22端口。使用p參數,可以修改這個端口。

  $ ssh -p 2222 user@host

上面這條命令表示,ssh直接連接遠程主機的2222端口。

5 ssh在Git中的使用

5.1 Github/GitLab 中爲什麼會用到 SSH?

Using the SSH protocol, you can connect and authenticate to remote servers and services. With SSH keys, you can connect to GitHub without supplying your username or password at each visit.

使用 SSH 協議,您可以連接和驗證遠程服務器和服務。

使用 SSH 密鑰,您可以連接到 GitHub,而無需在每次訪問時提供用戶名或密碼。

5.2 與 Github 主機進行通信的兩種方式

訪問遠程倉庫時可以選擇 SSH 或者 HTTPS 協議進行訪問。

(比如,與 gitlab 遠程倉庫進行進行安全認證可選擇使用 ssh 或者 https),兩者的表現 形式:

SSH  [email protected]:faner/test01.git
HTTPS  https://gitlab.com/faner/test01.git

當你選擇 HTTPS 時,會看到它有下面的一段提示"Create a personal access token on your account to pull or push via Https"簡單的翻譯一下就是"在您的帳戶上創建個人 訪問令牌,以通過 Https 進行 pull 或 push”,並且在你第一次將本地倉庫 push 到遠 程倉庫時會要求你輸入 gitlab 的用戶名和密碼。

5.3 GitHub/GitLab 中導入 SSH Key

SSH Key 導入 :導入過程比較簡單。

GitHub: 點擊用戶頭像 > Setting > SSH and GPG keys > New SSH key > 粘貼你生成的 公鑰(簡單的方法是用文本編輯器打開公鑰文件然後複製)。

那麼現在您已經設置了 SSH 密鑰,在下次克隆存儲庫時可以使用 SSH 的 URL。如果您已經 擁有通過 HTTPS 克隆的存儲庫,可以將存儲庫的遠程 URL 更改爲其 SSH URL 。

從用戶操作上來看,HTTPS 需要用戶輸入遠程倉庫的用戶名和密碼,比如需要輸入 gitlab 的帳號和密碼;SSH 無需輸入用戶和密碼。
問題:生成 ssh key 所使用的郵箱是否需要和本地 git 設置的郵箱相同?

本地 git 中配置的用戶名和郵箱會隨同提交日誌被公開到 GitHub 上,而非生成 ssh key 時使用的郵箱(兩者之間沒有必然關係)。

本文爲已有博客的整理,有關更多內容參考博客:

  1. SSH-key的生成與在Git中的使用
  2. SSH原理與運用(一):遠程登錄
    有關ssh的高級用法參考:
  3. SSH-key的生成與在Git中的使用
  4. SSH原理與運用(二):遠程操作與端口轉發
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章