SSH原理和應用

SSH(Secure SHell)是爲遠程登陸, 遠程通訊等設計的安全通訊協議, 由芬蘭研究員於1995年提出,其目的是用於替代非安全的Telnet、rsh、rexec等不安全的遠程Shell協議.算法

SSH提供身份認證,加密通訊,完整性校驗以及身份認證等功能. 工程人員常用SSH協議登陸雲服務器等遠程計算機, FTP, RPC等協議也可使用SSH提供的安全信道.shell

由於版權, 加密算法等緣由目前廣爲使用OpenSSH提供SSH服務.數據庫

使用SSH

OpenSSH分爲客戶端和服務端, Linux和Mac OS系統通常會自帶openssh-client。ubuntu

本地計算機上須要安裝客戶端, 遠程計算機上須要運行服務端。 SSH協議默認使用TCP22端口, 遠程計算機須要確保遠程計算機打開了22端口.安全

遠程計算機安裝服務端後可使用sudo service ssh start啓動, 或者使用sudo /etc/init.d/ssh start.bash

啓動成功後可使用service ssh status或者ps -e中查看ssh服務的狀態.服務器

遠程主機配置完畢後, 在本地主機使用ssh user@host命令能夠用戶user的身份登陸遠程主機host, 如ssh root@mycloud.com.併發

ssh服務可使用口令驗證(password)或者使用私鑰驗證(private-key)。ssh優先使用私鑰驗證, 若未配置私鑰則要求用戶輸入口令進行驗證, 該口令爲遠程計算機上帳戶的登陸口令.ssh

客戶端在要求客戶輸入口令以前, 會先會檢查本身的knows_hosts數據庫中(通常爲~/.ssh/know_hosts文件)是否已經包含當前服務端的密鑰指紋(ECDSA key fingerprint).ide

若包含則會繼續創建鏈接, 不然由用戶判斷是否相信當前客戶端. 若用戶不相信則中斷鏈接, 不然繼續創建鏈接, 並將當前服務端加入known_hosts中。

用戶在判斷是否相信當前服務端時需注意, 若該服務端爲真正的目標服務端, 則此後與此服務端通訊過程當中基本不會再受到中間人的威脅. 若發現錯誤信任了假冒的服務端, 則應儘快在known_hosts中刪除它的指紋, 避免計算機在通訊時默認相信該假冒者.

配置密鑰對

ssh-keygen是用於生成密鑰對的工具, 使用ssh-keygen生成RSA密鑰對:

$ssh-keygen -t rsa -C finley@gmail.com
Generating public/private rsa key pair.
Enter file in which to save the key (~/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ~/.ssh/id_rsa.
Your public key has been saved in ~/.ssh/id_rsa.pub.
The key fingerprint is:

上面的提示說明私鑰保存在~/.ssh/id_rsa, 公鑰保存在~/.ssh/id_rsa.pub. 若是必要的話也能夠爲私鑰設置口令.

使用man ssh-keygen能夠看到該命令的幫助, 最經常使用的選項有:

  • -q: 以靜默方式生成
  • -b bits: 指定位數
  • -t: 指定加密方式, 包括: dsa | ecdsa | ed25519 | rsa | rsa1
  • -N new_passphrase: 指定新的私鑰密碼
  • -C comment: 添加註釋, 一般是用戶的簽名
  • [-f output_keyfile]: 保存密鑰的文件, 默認爲~/.ssh/id_rsa

打開~/.ssh/id_rsa.pub能夠看到本身的公鑰, 將公鑰的內容添加到遠程計算機的~/.ssh/authorized_keys中,而後重啓遠程計算機的sshd使新的配置生效。

爲了保證安全,其它用戶不能擁有修改密鑰的權限,若系統檢測到其它用戶有密鑰的寫(w)權限將會拒絕使用該密鑰。所以,咱們將.ssh目錄權限設置爲700, 目錄下全部相關文件權限設置爲600

在終端中再次使用ssh命令登陸時就不須要輸入遠程計算機的登陸口令了。

一般狀況下咱們只須要一對密鑰, 就像咱們可使用同一個身份證在不一樣的地方證實咱們的身份同樣, 只不過防僞的不是難以僞造的證件而是難以猜想的私鑰.

傳輸文件

基於ssh傳輸文件是一個很是方便的功能, scp能夠經過ssh通道在本地計算機和遠程計算機之間傳遞文件.

scp會先使用ssh的認證方式創建安全連接, 而後完成文件傳輸, 完成傳輸後當即斷開鏈接.

在本地計算機的終端中執行scp命令從遠程計算機下載文件:

# format : scp user@host:remote_path local_path
$ scp ubuntu@qcloud:~/1.txt 1.txt

注意在本地終端執行, 而非使用ssh命令登陸的遠程終端.

scp命令與cp命令類似,第一個參數爲源地址,第二個參數爲目標地址, 只不過支持遠程路徑.

在複製目錄下的全部內容時一樣須要-r參數:

# format: scp -r user@host:remote_path local_path
$ scp -r ubuntu@qcloud:~/workspace workspace

目的地址寫爲遠程地址便可將本地文件上傳到遠程計算機:

# format: scp local_path user@host:remote_path
$ scp 1.txt ubuntu@qcloud:~/1.txt
# format scp -r local_path user@host:remote_path
$ scp -r workspace ubuntu@qcloud:~/workspace

使用跳板機

出於安全緣由,一般集羣中只有網關機能夠從外網登陸,內網中機器只能從網關機登陸。若先登陸網關機做爲跳板,再從網關機上登陸目標機則很是麻煩。

咱們可使用ssh的ProxyCommand功能自動使用跳板機登陸內網:

$ ssh username@internal -o ProxyCommand='ssh username@gateway -W %h:%p'

其中,ProxyCommand是登陸跳板機的ssh指令,internal是內網中目標機的地址。ssh username@internal將在跳板機上執行,internal一般爲目標機的內網ip地址。

注意,這種方式要求目標機的authorized_keys中包含本地計算機的密鑰。

配置主機別名

每次ssh登陸都須要輸入很長的指令是一件很麻煩的事情,咱們能夠在~/.ssh/config文件中配置主機別名極大的簡化登陸指令:

Host gateway # 主機別名,使用`ssh gateway`命令能夠直接登陸該主機
    Protocol 2  # ssh協議版本
    HostName example.com # 主機地址,支持IP或域名
    Port 22  # ssh服務端口號
    User ubuntu # 登陸用戶名
    IdentityFile ~/.ssh/id_rsa # 使用的私鑰文件

Host internal # 主機別名,這是一個自動跳轉示例
    Protocol 2
    HostName 192.168.1.111 # 目標機的內網ip地址,一般不使用域名
    Port 22 # 內網中目標機的ssh服務端口號
    User ubuntu # 登陸目標機的用戶名
    ProxyCommand ssh gateway -W %h:%p # 登陸跳板機的ssh指令,這裏使用上一條配置的別名
    IdentityFile ~/.ssh/id_rsa # 登陸跳板機的私鑰文件,該密鑰必須包含在跳板機的authorized_keys中

Host 10.10.0.* # 使用通配符的示例,登陸HostName符合通配符的主機均可以用該配置,如:`ssh ubuntu@10.10.0.1`
    Port 22
    User ubuntu   
    ProxyCommand ssh gateway -W %h:%p

端口轉發

SSH能夠經過端口轉發爲其它協議提供安全通訊. 端口轉發中涉及四臺主機:

  • 本地主機LocalHost: 運行SSH客戶端的主機, 即用戶操做的主機
  • 遠程主機RemoteHost: 運行SSH服務端的主機
  • 源主機SrcHost: 發送請求的主機
  • 目的主機DestHost: 請求要前往的主機

本地端口轉發是由ssh客戶端監聽本地端口, 並將發往該端口的通訊由遠程主機發往目標:

ssh -L LocalPort:DestHost:DestPort user@RemoteHost

配置本地轉發後:

  1. 本地SSH客戶端將監聽LocalPort端口
  2. 全部發往該本地端口的請求將被經過SSH信道發往遠程主機RemoteHost
  3. 遠程主機上的SSH服務端會將請求轉發到目標主機DestHost上的DestPort端口
  4. 目標主機的響應將被RemoteHost和LocalHost依次轉發, 原路返回來源主機

遠程轉發的過程正好與本地轉發相反:

ssh -R RemotePort:DestHost:DestPort user@RemoteHost

配置遠程轉發後:

  1. 遠程主機RemoteHost上的SSH服務端將監聽RemoteHost上的RemotePort端口
  2. 全部發送到RemoteHost得RemotePort端口上的請求將經過SSH信道發往本地
  3. 本地主機上的SSH客戶端將請求轉發到目標主機DestHost上的DestPort端口
  4. 目標主機的響應將被LocalHost和RemoteHost依次轉發, 原路返回來源主機

本地轉發只能請求發往固定的目的主機和目的端口, 而動態轉發則會根據請求的目的和協議決定轉發到的目的主機和目的端口.

ssh -D LocalPort user@RemoteHost

ssh客戶端將會監聽全部發往本地LocalPort的請求, 並經過遠程主機中轉, 轉發到請求的目的地址.

該過程與本地轉發相似, 不過目的主機與目的端口是根據請求動態決定的.

安全通訊原理

在進一步介紹認證過程以前, 須要先介紹一下對稱加密和非對稱加密的概念.

  • 對稱加密: 加密和解密的密鑰相同. 如典型的移位密碼: C代替A,D代替B...

    這裏向後移兩位就是密鑰, 得知向後移兩位後能夠將明文加密也能夠將密文解密.

  • 非對稱加密: 加密密鑰與解密密鑰不一樣. 一般加密密鑰公開(公鑰), 解密密鑰私有(私鑰), 且很難經過公鑰推斷私鑰.

非對稱加密方式下, 全部人均可以使用公鑰對明文進行加密, 可是隻有持有私鑰的人才能夠解密密文.

通常來講, 對稱加密方式的加解密速度比非對稱方式更快.

如今, 咱們能夠開始介紹SSH認證和安全通訊的原理了.

協議協商階段

創建SSH安全連接的第一個階段爲協議協商階段:

  1. 服務端監聽端口等待客戶端鏈接
  2. 客戶端發起TCP鏈接請求, 服務端接收到該請求後,向客戶端發送SSH協議版本信息.
  3. 客戶端接根據該版本信息與本身的版本,決定將要使用的SSH版本,並向服務端發送選用的SSH版本信息
  4. 服務端檢查是否支持客戶端的決定使用的SSH版本

至此,雙方完成協議協商。若是該過程當中,客戶端或服務端發送SSH版本沒法兼容,任何一方均可以斷開鏈接.

此時雙方創建明文信道, 均沒法確認對方身份.

服務端認證階段

隨後進入服務端認證階段:

  1. 服務端向客戶端發送下列信息:
    • 服務端身份公鑰(Host Key), 用於認證服務端身份
    • 服務端通訊公鑰(Server Key), 用於生成通訊加密密鑰
  2. 客戶端根據Host Key, 查詢known_hosts或交由用戶判斷是否信任該服務端.
    若信任則繼續,不然斷開鏈接

  3. 客戶端隨機生成會話密鑰(Session Key), 並使用服務端通訊公鑰(Server Key)加密後發給服務端

  4. 服務端用本身的私鑰解密獲得會話密鑰(Session Key)

本階段仍然使用明文信道, 當本階段結束時雙方都有了相同且安全的會話密鑰. 此後的通訊過程當中, 雙方將使用會話密鑰對稱加密進行安全通訊.

客戶端認證階段

隨後進入客戶端認證階段, 此階段雙方已創建對稱加密安全信道.

  • 口令方式: 客戶端提供用戶和口令,服務端進行匹配完成認證.

  • 密鑰方式:

    1. 客戶端發起一個Public Key認證請求
    2. 服務端檢查是否存在請求賬號的公鑰(通常在~/.ssh/authorized_keys文件中),以及其擁有的訪問權限, 若是沒有則斷開鏈接.
    3. 服務端使用客戶端發送的公鑰對一個隨機的256位的字符串進行加密,併發送給客戶端.
    4. 客戶端使用私鑰對字符串進行解密,並生成一個MD5值發送給服務端
    5. 服務端根據原始隨機字符串生成MD5值進行匹配, 確認客戶端身份

至此, 雙方互相確認對方身份並創建加密信道, 能夠正式進行安全通訊。

相關文章
相關標籤/搜索