1. 程式人生 > >SSH-key詳解及其在Git中的使用

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 - 簡書