SSH(Secure Shell)是一種加密的網絡傳輸協議,可在不安全的網絡中爲網絡服務提供安全的傳輸環境。(更多詳情可參閱維基百科 https://zh.wikipedia.org/wiki/Secure_Shell)
SSH協議基於的傳輸層協議爲TCP,默認端口22。(與Telnet的區別,Telnet明文傳輸內容故不安全。默認端口FTP 2一、SSH 2二、Telnet 23)html
大多數現代操做系統(包括macOS、大部分Linux、OpenBSD、FreeBSD、Solaris等系統)都提供了SSH協議的實現程序,但Windows系統未自帶SSH程序。Windows用戶可使用Cygwin來創建SSH服務。(補註:從 Win10 1809 和 Windows Server 2019 開始 Windows 已支持 OpenSSH Server)linux
SSH命令參數說明:Linux下可經過 man ssh 命令查看(中文翻譯版可參閱 http://linux.51yip.com/search/ssh)
web
先驗知識算法
ssh登陸須要用到公鑰、祕鑰,它們用於對文本內容進行加密或解密。一般用RSA加密方式,其是一種對稱加密,由公鑰加密的內容私鑰可解密、由私鑰加密的內容公鑰也可解密。公鑰能夠對外公開,私鑰則不能。關於RSA加密可參閱:RSA算法原理-阮一峯瀏覽器
經過ssh登陸遠程主機一般有兩種登陸方式:安全
一、輸密碼登陸:每次登陸都要輸密碼。內部原理:登陸時服務端發送服務端本身的公鑰給客戶端,客戶端用該公鑰加密密碼併發送到服務端,服務端用對應的私鑰解密,檢查密碼是否正確以肯定是否登陸成功。bash
第一次登陸時會警告公鑰是否可信任,以防止中間人攻擊返回的是中間人的公鑰,若用戶確認信任之則公鑰會保存到客戶端的$HOME/.ssh/known_hosts文件裏,之後再登陸就不會有警告了。服務器
二、祕鑰登陸(免密碼登陸):預先配置好祕鑰,以後每次登陸無需輸密碼。方法是在一臺機器上生成公鑰/私鑰對並將其中一個祕鑰放到另外一個機器上。有兩種:網絡
2.一、公鑰登陸:事先將客戶端的公鑰放到服務端上(本質上至關於配置免密登陸白名單)。內部原理:登陸時服務端發送一個隨機字符串給客戶端,客戶端用本身的私鑰加密併發送到服務端,服務端根據是否有事先存儲的公鑰能進行解密以肯定是否登陸成功。併發
2.二、私鑰登陸:事先將服務端的私鑰放到客戶端上,每次登陸時須要指定私鑰,可見此時私鑰至關於服務端的臨時密碼。
前一種方式須要對服務端進行配置,若要免密登陸的客戶端不少,則須要頻繁修改服務端配置;後一種能夠避免頻繁更改服務端,但比較不安全由於私鑰是不宜外泄的,這種模式只要有私鑰的人就能訪問服務器,可是例如阿里雲服務器就是這種訪問方式。
這裏介紹公鑰登陸的配置方法(假設機器A登陸機器B須要密碼,但不想每次登陸都需輸密碼):
一、A上生成密鑰對: ssh-keygen ,會在當前用戶目錄 ~/.ssh/ 下生成 id_rsa、id_rsa.pub 兩個文件,裏面內容分別爲私鑰、公鑰
二、將公鑰(id_rsa.pub裏的內容)追加到到B上 ~/.ssh/authorized_keys 文件中,文件不存在則新建。也可在A上經過命令完成該效果: ssh-copy-id -i ~/.ssh/id_rsa.pub <username of B>@<host of B>
三、重啓B上的ssh服務: sudo service sshd restart
四、以後若還不行,可檢查B上的/etc/ssh/sshd_config文件,確認以下內容沒被註釋:
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
參考資料:http://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html
可經過SSH執行遠程命令而不須要登陸遠程主機,示例:(更多可參閱:http://www.javashuo.com/article/p-ofwmixvl-dg.html)
# 主要命令格式
ssh user@10.5.6.47 "ls /home; pwd " # 執行基本命令,可有多個 ssh -t user@10.5.6.47 " top " # 對於須要交互(須要tty)的命令,經過ssh遠程執行時不會爲此會話分配tty,故ssh當即退出遠程主機從而須要交互的命令當即結束。經過 -t 參數顯示聲明須要爲會話分配tty以解決之 ssh user@10.5.6.47 " bash -s " < test.sh helloworld # 遠程執行本地主機上的腳本,參數爲往腳本傳的參數 ssh user@10.5.6.47 /home/user/test.sh helloworld # 遠程執行遠程主機上的腳本,參數爲往該腳本傳的參數
# 其餘trick示例
cd && tar czv src | ssh user@host 'tar xz' # 將$HOME/src/目錄下面的全部文件,複製到遠程主機的$HOME/src/目錄
ssh user@host 'tar cz src' | tar xzv # 將遠程主機$HOME/src/目錄下面的全部文件,複製到用戶的當前目錄
SSH是安全的,會自動加密和解密全部 SSH 客戶端與服務端之間的網絡數據。此外,SSH 還提供了一個很是有用的功能——端口轉發:它可以將其餘 TCP 端口的網絡數據經過 SSH 鏈接來轉發,並自動提供了相應的加密及解密服務。因 SSH 爲其餘 TCP 鏈接提供了一個安全的通道來進行傳輸,故也被稱做SSH隧道(SSH Tunnel)。例如,Telnet,SMTP,LDAP 這些 TCP 應用均可以從中得益,避免了用戶名,密碼以及隱私信息的明文傳輸。而與此同時,若是工做環境中的防火牆限制了一些網絡端口的使用但容許 SSH 鏈接,則也可經過 TCP 端口轉發來使用 SSH 進行通訊。
總的來講,SSH 端口轉發能提供兩大功能:
一、加密SSH Client與SSH Server間傳輸的數據
二、突破防火牆限制以間接完成一些以前沒法創建的 TCP 鏈接
從效果上看,端口轉發至關因而反向代理。
SSH端口轉發爲沒法直接任意互通但能經過SSH訪問的兩個網絡或機器間提供了一個互通的橋樑。分爲 本地端口轉發、遠程端口轉發、動態端口轉發三種。
這裏設想一種場景,假設有機器A、B、C、D,其間關係爲:A、B間可互通,C、D間可互通,AB與CD間不能自由互通(因設置了防火牆、白名單等,只有B能經過SSH訪問C、反之則不可。(想象AB、CD分別在不通的網段、兩個網段間只有B能經過SSH訪問到C且C只對B開放SSH的22端口)。
命令: ssh -L <forward port>:<target host>:<target port> <SSH server addr>
功能:將對SSH Client所在機器<forward port>端口的請求轉發到指定機器的指定端口(即 <target host>:<target port> )
原理:SSH Client所在機器分配一個 socket 監聽 <forward port> 端口,一旦此端口上有了鏈接,該鏈接就經安全通道轉發出去,同時SSH server所在機器和 <target host>:<target port> 創建鏈接。(請求的內部走向是SSH Client -> SSH Server -> 目標機,返回時原路返回)
應用場景:使得「內網」(SSH Client所在的)能訪問到不能直接訪問的其餘"網絡"
示例:假設D上有個web服務監聽8080端口,顯然,A、B都沒法直接訪問到該服務但C能夠。而B能夠經過SSH訪問C,此時在B上執行: ssh -g -fN -L 1000:hostD:8080 hostCSshAddr ,則A或B經過訪問B的1000端口就能訪問到D的web服務(內部走向是B -> C -> D)。
若沒有-g參數,則A訪問不了B的1000端口,只有B本身能夠。
若web服務在SSH server上(即目標主機與SSH服務端是同一個),則命令可簡爲: ssh -g -fN -L 1000:localhost:8080 hostCSshAddr ,可見這裏的localhost是相對於SSH server而言的。
(與本地端口轉發幾乎同樣,只不過轉發端口在SSH Server且請求的內部走向相反)
命令: ssh -R <forward port>:<target host>:<target port> <SSH server addr> ,注:不支持 -g 參數
功能:將對SSH Server所在機器<forward port>端口的請求轉發到指定機器的指定端口(即 <target host>:<target port> )
原理:SSH Server所在機器分配一個 socket 監聽 <forward port> 端口,一旦此端口上有了鏈接,該鏈接就經安全通道轉發出去,同時SSH Client所在機器和 <target host>:<target port> 創建鏈接。(請求的內部走向是SSH Server -> SSH Client -> 目標機,返回時原路返回)
應用場景:使得"外網"能訪問到"內網"(SSH Client所在的)
示例:若上述web服務在A,顯然,C、D沒法直接訪問該服務但B能夠。而B能夠經過SSH訪問C,此時在B上執行: ssh -fN -R 1000:hostA:8080 hostCSshAddr ,則C可經過訪問其1000端口就能訪問到A的web服務(內部走向是C -> B -> A)。
注:遠程端口轉發不支持-g參數故這裏沒法像本地端口轉發那樣經過 -g 參數讓D能訪問到A的web服務。解決:在SSH Server(即C)的/etc/ssh/sshd_config添加一行並重啓SSH服務: GatewayPorts yes
命令: ssh -D <foward port> <SSH server addr> ,可用參數與本地端口轉發的同樣
功能及原理:與本地端口轉發同樣,將對SSH Client所在機器<forward port>端口的請求轉發到SSH Server上,只不過設置時不用指定目的機器的host和port。SSH Client成爲一個反向代理,應用設置代理爲SSH Client後,應用發起請求時請求的內部走向也是SSH Client -> SSH Server -> 目標機,收到SSH Client轉發來的請求時SSH Server會與該請求的目標機鏈接。SSH 動態端口轉發是經過 Socks 協議實現的,建立動態端口轉發時 SSH 服務器就相似一個 Socks 代理服務器,因此這種轉發方式也叫 Socks 轉發。
應用場景:
做爲代理:把全部請求都轉發到目的機,以突破防火牆等限制。
提升安全性:讓那些不加密的網絡鏈接,所有改走SSH鏈接,從而提升安全性。
示例: 做爲反向代理——在本節首所述場景下,在B執行: ssh -g -fN -D 1000 hostCSshAddr ,至關於啓動了個反向代理服務。以後在A或B上設置Sockets代理(如在瀏覽器設置Sockets代理),地址爲 hostB:1000,則C、D上的服務均能被A或B訪問到。如A訪問服務hostD:8080,請求會經過 SSH Client B -> SSH Server C -> hostD:8080,由C完成對D的請求後原路返回結果。
注:
SSH 端口轉發是經過 SSH 鏈接創建起來的,故必須保持這個 SSH 鏈接以使端口轉發保持生效。一旦關閉了此鏈接,相應的端口轉發也會隨之關閉。
只能在創建 SSH 鏈接的同時建立端口轉發,而不能給一個已經存在的 SSH 鏈接增長端口轉發。
參考資料:
http://www.javashuo.com/article/p-sibzutlz-ke.html ssh端口轉發
http://www.ruanyifeng.com/blog/2011/12/ssh_port_forwarding.html