SSH-key詳解及其在Git中的使用

有必要先來了解什麼是SSH和什麼是SSH key。

SSH

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

傳統的FTP、Telnet是再網絡中明文傳送數據、用戶帳號和密碼,很容易受到中間人***。

SSH是目前較可靠,專爲遠程登錄會話和其他網絡服務提供安全性的協議。利用SSH協議可以有效防止遠程管理過程中的信息泄露問題。通過SSH可以對所有傳輸的數據進行加密,也能夠防止DNS欺騙和IP欺騙。

SSH-key詳解及其在Git中的使用

SSH只是一種協議,其開源實現有OpenSSH程序。

SSH服務端和客戶端程序

OpenSSH (OpenBSD Secure Shell) 是一套使用ssh協議,通過計算機網絡,提供加密通訊會話的計算機程序

如果需要作爲ssh的服務端,則需要安裝openssh。

如果僅是作爲ssh客戶端,在Linux中直接使用ssh命令即可。

Windows中的ssh客戶端程序有:

  • Putty
  • PuTTY Tray(Putty的加強版)
  • Bitvise 的 ssh client (功能多,免費)
  • Xshell (2017年被爆多版本存在後門)
  • SecureCRT(算了吧)
  • Cmder(開源的命令行工具,並且集成了Git for Windows和多個Unix命令,cmder的使用可參考 Cmder - 簡書 裏面有講到ssh agent的配置)

SSH Key

SSH 密鑰對 最直觀的作用:讓你方便的登錄到 SSH 服務器,而無需輸入密碼。由於你無需發送你的密碼到網絡中,SSH 密鑰對被認爲是更加安全的方式。

原因是:SSH利用SSH Key來進行前面提到的基於密鑰的安全驗證。

使用SSH key的步驟:

  • 在客戶端生成SSH key(密鑰對:公鑰和私鑰)
  • 在服務端的配置文件中加入你的公鑰。(比如我們需要再GitHub中粘貼你的公鑰)

生成密鑰對

ssh-keygen命令用於爲ssh生成、管理和轉換認證密鑰,它支持RSA和DSA兩種認證密鑰。

該命令的選項:

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

生成密鑰對時,有一個選項要求你設置密碼(passphrase),該密碼是用來保護你的私鑰的密碼。如果設置了則在使用私鑰時會要求你輸入這個密碼;一般不設置,記不住【之後還可更改此密碼,使用ssh-keygen -p】。

生成後最好將私鑰進行備份。另還有-C選項,用於爲指定註釋,通常使用自己的郵件名作爲註釋

-b bits選項 Specifies the number of bits in the key to create. For RSA keys, the minimum size is 1024 bits and the default is 2048 bits. Generally, 2048 bits is considered sufficient. DSA keys must be exactly 1024 bits

示例:爲了安全考慮使用RSA加密方式並指定密鑰長度 -b 2048(1024的密鑰長度能夠被破解,建議指定爲2048或4096)。

$ ssh-keygen -t rsa -C "[email protected]" -b 2048
Generating public/private rsa key pair.
Enter file in which to save the key
(/Users/your_user_directory/.ssh/id_rsa): 按回車鍵 (如果需要生成多對key,則輸入/home/users/.ssh/filename)
Enter passphrase (empty for no passphrase): 輸入密碼(一般不輸入密碼,直接回車)
Enter same passphrase again: 再次輸入密碼
...

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

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

實際操作的一次示例:

[fan 16:10:57]~$ ssh-keygen -t rsa -C "[email protected]" -b 2048
Generating public/private rsa key pair.
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 2048]----+
|   .+... .       |
|   +o.  o        |
| o.. oo..        |
|+o.   +*.o       |
|+..  E.=So .     |
|..    o== =      |
|     .=..+oo     |
|       +=o+= .   |
|      .++=.o*    |
+----[SHA256]-----+

公鑰是一串很長的字符;爲了便於肉眼比對和識別,所以有了指紋這東西;指紋位數短,更便於識別且與公鑰一一對應。

公鑰加密指紋fingerprint有兩種形式:

  • 之前的十六進制形式:16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48
  • 現在使用sha256哈希值並且使用base64進行格式:SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8

指紋的用處之一是在使用SSH第一次連接到某主機時,會返回該主機使用的公鑰的指紋讓你識別。示例:

The authenticity of host '某主機名' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no)?

簡單介紹一下:

公鑰用於給別人用來加密文件。公鑰就是一把鎖,你把鎖給別人,他用鎖鎖住東西后,除了你自己外其他人是沒有鑰匙(私鑰)的,都無法打開。配對的私鑰就是鑰匙。

必須保證使用你的公鑰的人明確知道這個公鑰一定是你的。你可以在網站或通過其它方式公佈你的公鑰,以便他人進行對照確認。由於公鑰很長,所以有了對應的指紋(指紋更易辨別,位數更少),可以通過指紋進行對照(公佈指紋)。

如何創建多個ssh key而不是覆蓋默認文件

在創建ssh key時自行輸入路徑和文件名稱,而非使用默認路徑和文件名即可。

或者使用 -f來指定文件名

ssh-keygen -t rsa -C "[email protected]" -f ~/.ssh/second-rsa

使用非默認的SSH key

對於OpenSSH客戶端(Linux默認安裝),需要在 ~/.ssh/config 文件中進行配置(如果沒有該文件則自行創建一個)。

分爲如下兩種情況。

1.爲不同服務器的同一用戶配置不同SSH key

好吧,這裏同一用戶在不同服務器上是可以使用同一個SSH key

Working with non-default SSH key pair paths

比如:你在GitLab上粘貼的公鑰(Public SSH keys)不是默認的密鑰對;此時要想讓你的ssh client正常與GitLab服務器通信,必須對ssh client進行配置,當通信對象爲GitLab服務器主機時,使用哪個私鑰(SSH private key)。

注意:這裏使用公鑰也是可以的

示例:

# GitLab.com server
Host gitlab.com
# 如果提示: Unsupported option "rsaauthentication",則可以選擇註釋掉該行
RSAAuthentication yes
IdentityFile ~/.ssh/private-key-filename-01

# Private GitLab server
Host gitlab.company.com
RSAAuthentication yes
IdentityFile ~/.ssh/private-key-filename

對於GitLab等:上傳到GitLab服務器中的SSH公鑰只能屬於單個用戶,你的SSH密鑰是您通過SSH推送代碼時的標識符;它需要唯一映射到單個用戶。也就是說,一個公鑰在該服務器上只能被一個賬戶使用;但是你可以在不同的服務器上使用同一個密鑰對,也可以在不同服務器上分別使用不同的密鑰對。

GitHub使用非默認密鑰對:

Host github.com
RSAAuthentication yes
# 也可以使用公鑰
IdentityFile ~/.ssh/FDGitHub_rsa.pub

配置完成後可以使用如下命令測試連接:

# 測試時替換掉 example.com
ssh -T [email protected]
# 例如 gitlab
ssh -T [email protected]
# 例如 github
ssh -T [email protected]
# 例如 coding
ssh -T [email protected]
# 例如 碼雲
ssh -T [email protected]
# bitbucket
ssh -T [email protected]

# 也可以使用下面的命令來調試連接
ssh -Tv [email protected]

如果測試時出現如下提示: Unsupported option "rsaauthentication",則可以選擇忽略或註釋掉配置文件中的 RSAAuthentication yes行。

2.配置多個賬戶

爲同一服務器配置不同賬戶,比如說你在coding上有兩個賬戶,那麼可以這樣在config文件中配置:

# coding
Host git.coding.net
User [email protected]
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa  //默認的私鑰

# second
Host git.coding.net
User [email protected]
PreferredAuthentications publickey
IdentityFile ~/.ssh/second_rsa  // 生成的第二個私鑰

SSH agent

ssh-agent命令是一種控制用來保存公鑰身份驗證所使用的私鑰的程序。在Linux中ssh-agent 在X會話登錄會話之初啓動,所有其他窗口或程序則以客戶端程序的身份啓動並加入到ssh-agent程序中。通過使用環境變量,可定位代理並在登錄到其他使用ssh機器上時使用代理自動進行身份驗證。

其實ssh-agent就是一個密鑰管理器,運行ssh-agent以後,使用ssh-add命令將私鑰交給ssh-agent保管,其他程序需要身份驗證的時候可以將驗證申請交給ssh-agent來完成整個認證過程。

另外如果您的私鑰使用密碼短語來加密了的話,每一次使用 SSH 密鑰對進行登錄的時候,您都必須輸入正確的密碼短語。而 SSH agent 程序能夠將您的已解密的私鑰緩存起來,在需要的時候提供給您的 SSH 客戶端。這樣子,您就只需要將私鑰加入 SSH agent 緩存的時候輸入一次密碼短語就可以了。這爲您經常使用 SSH 連接提供了不少便利。

有不少的 SSH agent 供您選擇,我們將爲您介紹幾種常用的 SSH agent,您可以根據您的需要進行選擇。

  • ssh-agent 是 OpenSSH 自帶的一個 SSH agent
  • GnuPG agent也許想要 GnuPG 來緩存您的私鑰。當然咯,有些用戶比較喜歡在 GnuPG 對話框來輸入 PIN 碼,這樣子管理密碼短語也是不錯的選擇。

ssh agent帶來的問題

在Linux中我並沒有遇到過因 ssh-agent 而帶來的問題,這裏說一下Windows中使用ssh時遇到的相關問題。

嘗試通過SSH進行身份驗證時,您可能會看到以下錯誤消息 :

當嘗試使用Git並通過SSH協議進行 clone, push,或 pull時,如果Github無法使用SSH agent提供的密鑰進行身份驗證,則可能會收到下面的某一條消息:

  • Permission denied (publickey)
  • No suitable response from remote
  • repository access denied

可能的原因:

  • 你的 公鑰 並沒有添加到服務器端。

  • 您的密鑰未加載到ssh agent中 。(如果您的SSH代理不知道爲Bitbucket提供密鑰,則連接將失敗。如果您最近重新啓動了系統,則可能會遇到此問題。 )解決方法:

    • 檢查相應的 ssh key 是否被加載:
    ssh-add -l
    • 如果沒有被加載,則使用下面的命令加載私鑰
    #後面可以同時跟多個私鑰
    ssh-add ~/.ssh/<private_key_file>  
    • 如果提示 "Could not open a connection to your authentication agent." 說明你的ssh agent並沒有運行;使用下面的命令運行ssh agent,再使用ssh-add命令添加你的ssh key。
    # macOS/Linux
    $ eval `ssh-agent`
    
    # 在Windows中的git-bash中
    $ eval $(ssh-agent) 

    還有個注意點,就是不要同時運行多個 ssh agent,可通過任務管理器或 ps命令進行查看。

Github/GitLab中使用SSH

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,而無需在每次訪問時提供用戶名或密碼。

GitHub/GitLab 中導入SSH Key

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

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

訪問遠程倉庫時可以選擇 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的用戶名和密碼。

經驗:由於我的ssh的config文件出現配置錯誤,並且ssh-agent也未運行,當我選擇[email protected]:faner/test01.git時提示有有誤(當時的情況就是使用ssh無法認證)

我就嘗試使用了https的https://gitlab.com/faner/test01.git路徑,之後就讓我輸入密碼併成功連接。

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

從用戶操作上來看,HTTPS需要用戶輸入遠程倉庫的用戶名和密碼,比如需要輸入gitlab的帳號和密碼;SSH無需輸入用戶和密碼。

問題:生成ssh key所使用的郵箱是否需要和本地git設置的郵箱相同?
本地git中配置的用戶名和郵箱會隨同提交日誌被公開到GitHub上,而非生成ssh key時使用的郵箱。

學習資料

瞭解SSH的最好方式是參見維基百科中的條目:Secure Shell - 維基百科,自由的百科全書

這裏是部分引用:

中間人***:就是存在另一個人或者一臺機器冒充真正的服務器接收用戶傳給服務器的數據,然後再冒充用戶把數據傳給真正的服務器。

SSH協議框架中最主要的部分是三個協議:

  1. 傳輸層協議(The Transport Layer Protocol):傳輸層協議提供服務器認證,數據機密性,信息完整性等的支持。
  2. 用戶認證協議(The User Authentication Protocol):用戶認證協議爲服務器提供客戶端的身份鑑別。
  3. 連接協議(The Connection Protocol):連接協議將加密的信息隧道複用成若干個邏輯通道,提供給更高層的應用協議使用。

在客戶端來看,SSH提供兩種級別的安全驗證:

  • 第一種級別(基於密碼的安全驗證),知道帳號和密碼,就可以登錄到遠程主機,並且所有傳輸的數據都會被加密。但是,可能會有別的服務器在冒充真正的服務器,無法避免被“中間人”***。
  • 第二種級別(基於密鑰的安全驗證),需要依靠密鑰,也就是你必須爲自己創建一對密鑰,並把公有密鑰放在需要訪問的服務器上。客戶端軟件會向服務器發出請求,請求用你的密鑰進行安全驗證。服務器收到請求之後,先在你在該服務器的用戶根目錄下尋找你的公有密鑰,然後把它和你發送過來的公有密鑰進行比較。如果兩個密鑰一致,服務器就用公有密鑰加密“質詢”(challenge)並把它發送給客戶端軟件。從而避免被“中間人”***。

在服務器端,SSH也提供安全驗證:

在第一種方案中,主機將自己的公用密鑰分發給相關的客戶端,客戶端在訪問主機時則使用該主機的公開密鑰來加密數據,主機則使用自己的私有密鑰來解密數據,從而實現主機密鑰認證,確保數據的保密性。 在第二種方案中,存在一個密鑰認證中心,所有提供服務的主機都將自己的公開密鑰提交給認證中心,而任何作爲客戶端的主機則只要保存一份認證中心的公開密鑰就可以了。在這種模式下,客戶端必須訪問認證中心然後才能訪問服務器主機。

必看: Secure Shell - 維基百科,自由的百科全書

如果要詳細瞭解,請認真參考:SSH keys (簡體中文)
實戰:Connecting to GitHub with SSH
Readme · Ssh · Help · GitLab
配置 SSH 公鑰訪問代碼倉庫 – CODING 幫助中心
Bitbucket上列出了各種ssh相關問題和解決方法:Troubleshoot SSH issues - Atlassian Documentation

強烈建議學習的幾篇SSH文章:
阮一峯:
SSH原理與運用(一):遠程登錄
SSH原理與運用(二):遠程操作與端口轉發
Asrchlinux wiki:
Secure Shell (簡體中文)
SSH keys (簡體中文)

來自於我的簡書:faner - 簡書

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章