SSH 協議及 OpenSSH 實現

SSH

SSH(Secure Shell 的縮寫)是一種網絡協議,用於加密兩臺計算機之間的通信,並且支持各種身份驗證機制

1996年提出了 SSH 2 協議(或者稱爲 SSH 2.0),爲現在各種實現採用的協議

實現

協議只是理論,只有實現(程序)才能應用

程序軟件架構採用服務器-客戶端模式(Server - Client),客戶端向服務器發出請求,服務器接收客戶端的請求

各種實現

客戶端

OpenSSH 的客戶端實現是二進制程序 ssh

命令

ssh [options] user@hostname [command]

登出:logout、exit、ctrl + D

options

-i

指定用於登錄的私鑰,默認爲~/.ssh/id_rsa(rsa算法)

-p

指定客戶端連接遠程服務器端口,默認爲22,如果服務器監聽其他端口,則客戶端需要通過該參數指定

-t

在 ssh 直接運行遠端命令時,提供一個互動式 Shell

command

SSH 登錄成功後,用戶就進入了遠程主機的命令行環境,終端提示符是遠程主機的提示符。默認情況下會分配一個 tty,提供交互式 Shell 環境

如果命令後面直接添加 command,則不分配tty,不提供交互式 Shell 環境,而是直接執行 command,並將 command 的執行結果輸出到本地終端,然後退出登錄。如果命令需要交互,則可以通過 -t 參數,分配一個tty——交互式 Shell 環境,ssh 保持登錄狀態,直到登出

https://www.cnblogs.com/sparkdev/p/6842805.html

  • 命令要放在單引號中,多個命令用分號隔開

    ssh [email protected] 'ls; cat hello.txt'
    
  • 執行遠程服務器腳本

    ssh [email protected] '/root/update.sh'
    
    • 需要腳本的絕對路徑
  • 執行本地腳本

    ssh [email protected] < update.sh
    
    • 通過重定向 stdin,本地的腳本在遠程服務器上被執行

相關文件

  • known_hosts

    客戶端保存已登錄過的 SSH 服務器的公鑰

  • id_rsa

    用於 SSH 協議版本2 的 RSA 私鑰

  • id_rsa.pub

    用於SSH 協議版本2 的 RSA 公鑰

  • /etc/ssh/ssh_config

    全局配置文件

  • ~/.ssh/config

    用戶個人的配置文件,優先級高於全局配置文件

    默認沒有該文件,自己創建

配置

  • 配置文件的每一行,就是一個配置命令。配置命令與對應的值之間,可以使用空格,也可以使用等號

    Compression yes
    # 等同於
    Compression = yes
    
  • 配置命令

    • Host

      指定連接的域名或 IP 地址,也可以是別名,支持通配符。Host命令後面的所有配置,都是針對該主機的,直到下一個Host命令爲止。

      Host *.example.com
          PreferredAuthentications publickey
          IdentityFile ~/.ssh/996icu_id_rsa
          ForwardAgent yes
      Host github
          HostName github.com
          PreferredAuthentications publickey
          IdentityFile ~/.ssh/996icu_id_rsa
      

      使用縮進來更好的表示

    • HostName

      Host命令使用別名的情況下,HostName指定域名或 IP 地址。

      HostName myserver.example.com
      
    • IdentityFile

      指定私鑰文件

      IdentityFile keyfile
      
    • ForwardAgent

      是否允許代理

       ForwardAgent yes
      
    • PreferredAuthentications

      指定各種登錄方法的優先級

      PreferredAuthentications publickey,hostbased,password
      

長連接

用ssh連接服務端,一段時間不操作或屏幕沒輸出(比如複製文件)的時候,會自動斷開

服務端設置

找到/etc/ssh/sshd_config,大約126-127行,取消註釋,並修改數值

# 30表示30s給客戶端發送一次心跳
ClientAliveInterval 30
# 3此客戶端沒有返回心跳,則會斷開連接
ClientAliveCountMax 3

修改服務端的配置往往會比較麻煩,也涉及到權限問題,以及安全問題。推薦修改客戶端

客戶端配置(推薦)

如果是想讓主機所有用戶都生效,修改/etc/ssh/ssh_config
如果只想讓本人生效,則修改 ~/.ssh/config

Host *
    ServerAliveInterval 30
    ServerAliveCountMax 3

如果此處還有一個配置項叫 SendEnv LANG LC_*,老高建議最好註釋掉,否則如果本地是中文環境,而服務器沒有對應的中文語言選項時系統可能會出現很多莫名其妙的BUG,所以保持原始英文語言環境爲上。

一次性配置

如果只是想臨時使用一次,完全可以不用大動干戈地找配置文件改,ssh命令支持直接注入參數,如下:

ssh -o ServerAliveInterval=30 user@host

查看是否生效

想測試是否生效,我們直接ssh到服務器後等一會兒看效果就行,但是如果想看到服務器和客戶端發送心跳包的過程,可以這樣

ssh -o ServerAliveInterval=30 -vvv user@host

等30s後我們應該可以看到如下字樣,說明我們在指定時間發送了心跳給服務器,服務器也有應答。同理如果我們在服務器也打開了心跳,則應該是先收到服務器的心跳然後再應答。

debug3: send packet: type 80
debug3: receive packet: type 82

更多研究可以參考Linux使用ssh超時斷開連接的真正原因

服務器

密鑰變更

  1. 重裝SSH服務器
  2. 兩臺服務器擁有同樣的IP,不同的密鑰

客戶端連接時就會發生公鑰不吻合的情況,中斷連接,此時客戶端需要將原來的公鑰從~/.ssh/known_hosts文件中刪除,重新驗證遠程服務器。因此

會出現一個 konw_hosts.old 的文件

ssh-keygen -R hostname
# ssh-keygen -f "/home/lfp/.ssh/known_hosts" -R "192.168.200.2"
  • hostname 公鑰發生變更的主機名

相關文件

  • authorized_keys

    服務器保存已登錄的客戶端的公鑰

    如果不存在則手動創建,文件的權限要設爲644,即只有文件所有者才能寫

    chmod 644 ~/.ssh/authorized_keys
    

遠程登錄

密碼登錄

流程

  1. 服務器驗證

    連接遠程服務器需要驗證其是否可信,遠程服務器會發送自己的指紋(公鑰),如果在本地~/.ssh/known_hosts 文件中沒有該公鑰,則提示用戶該服務器指紋是陌生的,是否需要繼續連接,輸入yesno,如果輸入yes則認爲該服務器的公鑰可信,加入本地~/.ssh/known_hosts文件中,下次再次連接時則不提示。

    服務器指紋指 SSH-Server 生成的密鑰對,在安裝 sshd 時默認會在/etc/ssh目錄下生成密鑰對,例如 ssh_host_xxx_key 及 ssh_host_xxx_key.pub

    ssh [email protected]
    The authenticity of host 'foo.com (192.168.121.111)' can't be established.
    ECDSA key fingerprint is SHA256:Vybt22mVXuNuB5unE++yowF7lgA/9/2bLSiO3qmYWBY.
    Are you sure you want to continue connecting (yes/no)? yes # 輸入yes
    Warning: Permanently added 'foo.com (192.168.121.111)' (RSA) to the list of known hosts
    
  2. 輸入登錄密碼

    客戶端就會跟服務器建立連接後,SSH-Client 用服務器的公鑰,將所要登錄的用戶的密碼加密後,發送給服務器

  3. 登錄密碼驗證

    遠程服務器的SSH-Server利用自己的私鑰解密,驗證登錄密碼是否正確,如果正確則允許登錄

密鑰登錄

SSH 默認採用密碼登錄,這種方法有很多缺點,簡單的密碼不安全,複雜的密碼不容易記憶,每次手動輸入也很麻煩。密鑰登錄是比密碼登錄更好的解決方案

SSH 密鑰登錄採用非對稱加密,兩個密鑰成對使用,分爲公鑰(public key)和私鑰(private key)

  • 使用公鑰加密,只有使用對應的私鑰解密
  • 使用私鑰簽名,只有使用對應的公鑰解密

流程

  1. 手動將客戶端的公鑰放入遠程服務器的指定位置
  2. 客戶端向服務器發起 SSH 登錄的請求
  3. 服務器收到用戶 SSH 登錄的請求,發送一些隨機數據給用戶,要求用戶證明自己的身份。
  4. 客戶端收到服務器發來的數據,使用自己的私鑰對數據進行簽名,然後再發還給服務器。
  5. 服務器收到客戶端發來的加密簽名後,使用對應的公鑰解密,然後跟原始數據比較。如果一致,就允許用戶登錄

生成密鑰

ssh-keygen -t rsa -C "[email protected]"
# 代碼參數含義:
# -t 指定密鑰類型,默認是 rsa ,可以省略。
# -C 設置註釋文字,比如郵箱。
# -f 指定密鑰文件存儲文件名。

# 以上代碼省略了 -f 參數,因此,運行上面那條命令後會讓你輸入一個文件名,用於保存剛纔生成的SSH key
Generating public/private rsa key pair.
Enter file in which to save the key (/home/lfp/.ssh/id_rsa): /home/lfp/.ssh/996icu_id_rsa
# 可以不輸入文件名,使用默認文件名(推薦),就會生成 id_rsa 和 id_rsa.pub 兩個祕鑰文件。
# 公司的可以修改文件名 

# 接着又會提示你輸入兩次密碼(該密碼是你push文件的時候要輸入的密碼,而不是github賬號的密碼),
# 可以不輸入密碼,直接按回車(兩下)。那麼push的時候就不需要輸入密碼,直接提交到github上了,如:

Enter passphrase (empty for no passphrase): 
Enter same passphrase again:
#接下來,就會顯示如下代碼提示:
Your identification has been saved in /home/lfp/.ssh/996icu_id_rsa.
Your public key has been saved in /home/lfp/.ssh/996icu_id_rsa.pub.
The key fingerprint is:
SHA256:U2QI4FzNgyBr2z2gG2iIZAPHM2FgHjGVA6FFa5w [email protected]
The key's randomart image is:
+---[RSA 2048]----+
|o&%o+oo= .o      |
|O=XB .. =o       |
|+Eoo=    ..      |
|B+.+ o   .       |
|+.+ . o S        |
|.  o   . .       |
|  .              |
|                 |
|                 |
+----[SHA256]-----+
#當你看到上面這段代碼時,那就說明,你的 SSH key 已經創建成功

上傳密鑰

生成密鑰以後,公鑰必須上傳到服務器,才能使用公鑰登錄。

OpenSSH 規定,用戶公鑰保存在服務器的~/.ssh/authorized_keys文件

執行如下命令或手動複製粘貼

cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

端口轉發

https://wangdoc.com/ssh/port-forwarding.html#遠程轉發

https://blog.mythsman.com/post/5d301903976abc05b3454691/

代理轉發

https://docs.github.com/cn/developers/overview/using-ssh-agent-forwarding

參考

https://wangdoc.com/ssh/index.html

https://www.ssh.com/academy/ssh/openssh

應用

github

添加公鑰

添加 SSH key 到 github上

  • 複製 id_rsa.pub 公鑰

  • 點擊頭像--->Settings--->SSH and GPG keys--->New SSH key--->將公鑰粘貼到裏面,並取個名字即可

  • 測試是否成功

    ssh -T [email protected]
    

    看到如下內容,則設置成功

    Hi xxx! You've successfully authenticated, but GitHub does not provide shell access.

添加ssh後仍需要輸入密碼

  1. git config --list 查看當前項目對應的遠程地址 remote.origin.url,要改爲 git開頭的地址
  2. git remote set-url origin [email protected]

FAQ

Connection closed by remote host

  • 如果原來是可以用ssh連接的, 突然連接不上通常是連接數過多導致的

  • 修改最大連接數

    # 找到配置文件 /etc/ssh/sshd_config
    # 去掉前面的 "#" 並把連接數改大
    MaxSession 10
    

    重啓 service sshd reload

  • 每次退出ssh時,使用 exit 斷開連接

Enter passphrase for key '/root/.ssh/id_rsa'

https://stackoverflow.com/a/34800766

  • 如果創建 ssh key 的時候設置了密碼,則每次使用ssh免密登錄的時候都需要輸入密碼

解決辦法:

  1. 修改(刪除)密碼

     ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]
    

    將原始密碼 123456 改爲 ''(空)

    ssh-keygen -p -P 123456 -N '' -f ~/.ssh/id_rsa
    
  2. 將密碼添加到 ssh-agent

    如果不想在每次使用 SSH 密鑰時重新輸入密碼,您可以將密鑰添加到 SSH 代理,讓它管理您的 SSH 密鑰並記住您的密碼。

ssh : connect to host xxx port 22:Connection refused

原因是被訪問主機沒有啓動 OpenSSH

查看本機是否啓動 OpenSSH

ps -ef | grep ssh
# 或
systemctl status sshd

ubuntu 需要安裝 openssh-server

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