## SSH
* SSH是非對稱加密,也就是公鑰加密。
* 對稱加密(也稱為秘鑰加密)
* 非對稱加密(也稱公鑰加密)
## SSH原理圖

1. 遠程Server收到Client端用戶TopGun的登錄請求,Server把自己的公鑰發給用戶。
2. Client使用這個公鑰,將密碼進行加密。
3. Client將加密的密碼發送給Server端。
4. 遠程Server用自己的私鑰,解密登錄密碼,然后驗證其合法性。
5. 若驗證結果,給Client相應的響應。
> 私鑰是Server端獨有,這就保證了Client的登錄信息即使在網絡傳輸過程中被竊據,也沒有私鑰進行解密,保證了數據的安全性,這充分利用了非對稱加密的特性。
## 連接server的兩種情況。
### 1. 基于口令的認證
從上面的描述可以看出,問題就在于**如何對Server的公鑰進行認證?**在https中可以通過CA來進行公證,可是SSH的**publish key**和**private key**都是自己生成的,沒法公證。只能通過Client端自己對公鑰進行確認。通常在第一次登錄的時候,系統會出現下面提示信息:
~~~
The authenticity of host 'ssh-server.example.com (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)?
~~~
上面的信息說的是:無法確認主機ssh-server.example.com(12.18.429.21)的真實性,不過知道它的公鑰指紋,是否繼續連接?
> 之所以用fingerprint代替key,主要是key過于長(RSA算法生成的公鑰有1024位),很難直接比較。所以,對公鑰進行hash生成一個128位的指紋,這樣就方便比較了。
如果輸入**yes**后,會出現下面信息:
~~~
Warning: Permanently added 'ssh-server.example.com,12.18.429.21' (RSA) to the list of known hosts.
Password: (enter password)
~~~
該host已被確認,并被追加到文件**known\_hosts**中,然后就需要輸入密碼。
### 2.免密登陸的實現原理(基于公鑰認證)

1. Client將自己的公鑰存放在Server上,追加在文件authorized\_keys中。
2. Server端接收到Client的連接請求后,會在authorized\_keys中匹配到Client的公鑰pubKey,并生成隨機數R,用Client的公鑰對該隨機數進行加密得到pubKey(R)
,然后將加密后信息發送給Client。
3. Client端通過私鑰進行解密得到隨機數R,然后對隨機數R和本次會話的SessionKey利用MD5生成摘要Digest1,發送給Server端。
4. Server端會也會對R和SessionKey利用同樣摘要算法生成Digest2。
5. Server端會最后比較Digest1和Digest2是否相同,完成認證過程。
## SSH實踐
### 1.生成密鑰操作
經過上面的原理分析,下面三行命令的含義應該很容易理解了:
~~~
$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
$ chmod 0600 ~/.ssh/authorized_keys
~~~
ssh-keygen是用于生產密鑰的工具。
* \-t:指定生成密鑰類型(rsa、dsa、ecdsa等)
* \-P:指定passphrase,用于確保私鑰的安全
* \-f:指定存放密鑰的文件(公鑰文件默認和私鑰同目錄下,不同的是,存放公鑰的文件名需要加上后綴.pub)
首先看下面~/.ssh中的四個文件:

1. id\_rsa:保存私鑰
2. id\_rsa.pub:保存公鑰
3. authorized\_keys:保存已授權的客戶端公鑰
4. known\_hosts:保存已認證的遠程主機ID(關于known\_hosts詳情,見文末更新內容)
四個角色的關系如下圖所示:

> 需要注意的是:一臺主機可能既是Client,也是Server。所以會同時擁有authorized\_keys和known\_hosts。
### 登錄操作
~~~
# 以用戶名user,登錄遠程主機host
$ ssh user@host
# 本地用戶和遠程用戶相同,則用戶名可省去
$ ssh host
# SSH默認端口22,可以用參數p修改端口
$ ssh -p 2017 user@host
~~~