ssh的軟件架構是服務器-客戶端模式(Server - Client)
在這個架構中,SSH軟件分成兩個部分:
- 向服務器發出請求的部分,稱為客戶端 client,OpenSSH的實現位ssh
- 接收客戶端發出的請求的部分,稱為服務器 server, OpenSSH的實現位sshd
OpenSSH還提供一些輔助工具軟件(比如ssh-keygen、ssh-agent)和專門的客戶端工具(比如scp和ftp)
SSH 客戶端
執行遠程命令
另一種執行遠程命令的方法,是將命令直接寫在ssh
命令的后面。
$ ssh username@hostname command
采用這種語法執行命令的時候,不會提供互動式的shell環境。
如果需要互動式環境需要添加一個參數-t
ssh命令行配置項
-c
: 指定加密算法
-C
: 表示壓縮數據傳輸
-D
: 指定本機的Socks監聽端口,該端口收到的請求,都將轉發到遠程的SSH主機,又稱動態端口轉發
ssh -D 1080 server
將本機1080端口收到的請求,都轉發到服務器server
-f
: 表示SSH連接在后台運行
-F
: 參數指定配置文件
-i
: 指定私鑰
-l
: 指定遠程登錄的賬戶名
-L
: 設置本地端口轉發
$ ssh -L 9999:targetServer:80 user@remoteserver
上面命令中,所有發向本地9999
端口的請求,都會經過remoteserver
發往 targetServer 的 80 端口,這就相當於直接連上了 targetServer 的 80 端口
-m
: 指定校驗數據完整性的算法(message authentication code,簡稱MAC)
-N
: 用於端口轉發,表示建立的SSH只用於端口轉發,不能執行遠程命令
-o
: 指定一個配置命令
-p
: 指定ssh客戶端連接的服務器端口
-q
: 安靜模式(quiet),不向用戶輸出任何警告信息
-R
: 指定遠程端口轉發
$ ssh -R 9999:targetServer:902 local
上面命令需在跳板服務器執行,指定本地計算機local
監聽自己的 9999 端口,所有發向這個端口的請求,都會轉向 targetServer 的 902 端口。
-t
: 參數在ssh直接運行遠端命令時,提供一個互動式Shell
-v
: 參數顯示詳細信息,v可以重復多次,表示信息的詳細程度
-V
: 輸出ssh客戶端的版本
客戶端配置文件
個人配置文件的優先級要高於全局配置文件
全局配置文件:/etc/ssh/ssh_config
個人配置文件:~/.ssh/config
功能
按照不同的服務器,列出各自的連接參數,從而不必每一次登錄都輸入重復的參數
Host *
Port 2222
Host remoteserver
HostName remote.example.com
User neo
Port 2112
Hsot *
代表對所有的主機都生效,縮進不是必須的
remoteserver只是一個別名,可以直接使用ssh remoteserver
命令,就會套用config里面的參數進行連接
SSH密鑰登錄
密鑰(key)是一個非常大的數字,通過加密算法得到。對稱加密只需要一個密鑰,非對稱加密需要兩個密鑰成對使用,分為公鑰和私鑰。
如果數據使用公鑰加密,那么只有使用對應的私鑰才能解密,其他密鑰都不行;反過來,如果使用私鑰加密(一般稱之為簽名)也只能使用對應的公鑰解密。
驗證步驟
預備步驟,客戶端通過ssh-keygen
生成自己的公鑰和私鑰。
ssh-keygen -t dsa
-t
參數用來指定密鑰的加密算法,一般會選擇dsa
算法或者rsa
算法,此參數必須要指定
第一步,手動將客戶端的公鑰放入遠程服務器的指定位置。
第二步,客戶端向服務器發起 SSH 登錄的請求。
第三步,服務器收到用戶 SSH 登錄的請求,發送一些隨機數據給用戶,要求用戶證明自己的身份。
第四步,客戶端收到服務器發來的數據,使用私鑰對數據進行簽名,然后再發還給服務器。
第五步,服務器收到客戶端發來的加密簽名后,使用對應的公鑰解密,然后跟原始數據比較。如果一致,就允許用戶登錄。
生成密鑰以后,建議修改它們的權限,防止其他人讀取。
$ chmod 600 ~/.ssh/id_rsa
$ chmod 600 ~/.ssh/id_rsa.pub
手動上傳公鑰
OpenSSH規定,用戶公鑰保存在服務器的~./ssh/authorized_keys
文件。要以哪個用戶的身份登錄到服務器,密鑰就必須保存在該用戶主目錄的~/.ssh/authorized_keys
文件。只要把公鑰添加到這個文件之中,就相當於公鑰上傳到服務器了。每個公鑰占據一行。如果該文件不存在,可以手動創建。
用戶可以手動編輯該文件,把公鑰粘貼進去,也可以在本機計算機上,執行下面的命令。
$ cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
注意,authorized_keys
文件的權限要設為644
,即只有文件所有者才能寫。如果權限設置不對,SSH 服務器可能會拒絕讀取該文件。
ssh-copy-id 自動上傳公鑰
OpenSSH 自帶一個ssh-copy-id
命令,可以自動將公鑰拷貝到遠程服務器的~/.ssh/authorized_keys
文件。如果~/.ssh/authorized_keys
文件不存在,ssh-copy-id
命令會自動創建該文件。
用戶在本地計算機執行下面的命令,就可以把本地的公鑰拷貝到服務器。
$ ssh-copy-id -i key_file user@hosts
上面命令中,-i
參數用來指定公鑰文件,user
是所要登錄的賬戶名,host
是服務器地址。如果省略用戶名,默認為當前的本機用戶名。執行完該命令,公鑰就會拷貝到服務器。
注意,公鑰文件可以不指定路徑和.pub
后綴名,ssh-copy-id
會自動在~/.ssh
目錄里面尋找。
$ ssh-copy-id -i id_rsa user@host
端口轉發
SSH除了可以登錄服務器,還可以作為加密通信的中介,充當兩台服務器之間的通信加密跳板,使得原本不加密的通信變成加密通信。這個功能稱為端口轉發(port forwarding),又稱SSH隧道(tunnel)。
主要有兩個作用:
- 將不加密數據放在SSH安全連接里面傳輸,增加不安全網絡服務的安全性。
- 作為數據通信的加密跳板,繞過網絡防火牆
三種使用方法:
- 動態轉發
- 本地轉發
- 遠程轉發
動態轉發
動態轉發指的是,本機與SSH服務器之間創建一個加密連接,然后本機內部針對某個端口的通信,都通過這個加密連接轉發。對於本地轉發和遠程轉發,都存在兩個一一對應的端口,分別位於SSH的客戶端和服務端,而動態轉發只是綁定了一個本地端口,而目標地址:目標端口都是不固定的。目標地址:目標端口是由發起的請求決定的。
使用場景
-
訪問所有外部網站,都通過SSH轉發。(可做為簡易VPN)
-
SSH服務器端運行了多個服務,使用了不同的端口,本地主機需要訪問這些服務
為什么需要動態端口轉發?
- 由於防火牆的限制,本地主機並不能直接訪問遠程主機上的服務
- 存在多個服務的話,為每個端口分別創建本地端口轉發非常麻煩
ssh -D localhost:port tunnel-host
# example
ssh -D localhost:2121 root@112.3.42.245
在本地發起的請求,需要由Socket代理(Socket Proxy))轉發到SSH綁定的2121端口。
以瀏覽器的proxy代理為例,瀏覽器發起的請求都會轉發到2121端口,然后通過SSH轉發到真正的請求地址。
若Node.js服務運行在遠程雲主機上,則在瀏覽器中訪問localhost:3000即可以訪問。如果主機B1能夠訪問外網的話,則可以訪外網……
除了使用瀏覽器外,也可以通過命令行訪問
$ curl -x socks5://localhost:2121 http://www.example.com
本地轉發
一般來講,雲主機的防火牆默認只打開了22端口,如果需要訪問3000端口的話,需要修改防火牆。為了保證安全,防火牆需要配置允許訪問的IP地址。但是,本地公網IP通常是網絡提供商動態分配的,是不斷變化的。這樣的話,防火牆配置需要經常修改,就會很麻煩。
本地轉發就是將發送到本地端口的請求,轉發到目標端口。這樣就可以通過訪問本地端口,來訪問目標端口的服務。
ssh -L 本機地址:本地端口:目標地址:目標端口
通過本地端口轉發,可以將發送到本地主機端口的請求,轉發到遠程主機端口上。
# 在本地主機登陸遠程主機,並進行本地端口轉發
ssh -L localhost:2000:local:3000 root@103.59.22.17
這樣,在本地主機A1上可以通過訪問http://localhost:2000來訪問遠程雲主機3000端口上的服務。
實際上,-L選項中的本地網卡地址是可以省略的,這時表示2000端口綁定了本地主機的所有網卡:
# 在本地主機A1登陸遠程雲主機B1,並進行本地端口轉發。2000端口綁定本地所有網卡
ssh -L 2000:localhost:3000 root@103.59.22.17
若本地主機A2能夠訪問A1,則A2也可以通過A1訪問遠程遠程雲主機B1上的Node.js服務。
另外,-L選項中的目標地址也可以是其他主機的地址。假設遠程雲主機B2的局域網IP地址為192.168.59.100,則可以這樣進行端口轉發:
# 在本地主機A1登陸遠程雲主機B1,並進行本地端口轉發。請求被轉發到遠程雲主機B2上
ssh -L 2000:192.168.59.100:3000 root@103.59.22.17
遠程轉發
應用場景:本地主機運行了一個服務,端口為3000,而本地主機沒有一個固定的公網ip地址,遠程主機需要訪問這個服務
如果本地主機有一個獨立公網ip,那么我們可以通過本地轉發來訪問本地主機上的服務。
但是大部分的時候本地主機都是在局域網內,與很多設備共享一個ip。
因此遇到這樣的情況,我們需要遠程轉發來解決。
定義
遠程轉發就是將發送到遠程端口的請求,轉發到目標端口。這樣就可以通過訪問遠程端口,來訪問目標端口的服務。
-R 遠程網卡地址:遠程端口:目標地址:目標端口
通過遠程轉發,可以將發送到遠程雲主機2000端口的請求,轉發到本地主機的3000端口。
# 在本地主機A1登陸遠程主機B1,並進行遠程端口轉發
ssh -R localhost:2000:local:3000 root@103.59.22.17
這樣,在遠程主機A1可以通過訪問http://localhost:2000來訪問本地主機的服務。
同理,遠程網卡地址可以省略,目標地址也可以是其他主機地址。假設本地主機A2的局域網IP地址為192.168.0.100
# 在本地主機A1登陸遠程雲主機B1,並進行遠程端口轉發
ssh -R 2000:192.168.0.100:3000 root@103.59.22.17
參考文章
1.https://wangdoc.com/ssh/port-forwarding.html
2.https://blog.fundebug.com/2017/04/24/ssh-port-forwarding/