SSH 是 Linux 系統的登錄工具,現在廣泛用於服務器登錄和各種加密通信。
SSH基本知識
SSH(Secure Shell 的縮寫)是一種網絡協議,用於加密兩台計算機之間的通信,並且支持各種身份驗證機制。
實務中,它主要用於保證遠程登錄和遠程通信的安全,任何網絡服務都可以用這個協議來加密。
1、SSH是什么
歷史上,網絡主機之間的通信是不加密的,屬於明文通信。這使得通信很不安全,一個典型的例子就是服務器登錄。登錄遠程服務器的時候,需要將用戶輸入的密碼傳給服務器,如果這個過程是明文通信,就意味着傳遞過程中,線路經過的中間計算機都能看到密碼,這是很可怕的。
SSH 就是為了解決這個問題而誕生的,它能夠加密計算機之間的通信,保證不被竊聽或篡改。它還能對操作者進行認證(authentication)和授權(authorization)。明文的網絡協議可以套用在它里面,從而實現加密。
2、歷史
1995年,芬蘭赫爾辛基工業大學的研究員 Tatu Ylönen 設計了 SSH 協議的第一個版本(現稱為 SSH 1),同時寫出了第一個實現(稱為 SSH1)。
OpenSSH 隨 OpenBSD 2.6 版本一起提供,以后又移植到其他操作系統,成為最流行的 SSH 實現。目前,Linux 的所有發行版幾乎都自帶 OpenSSH。
3、SSH架構
SSH 的軟件架構是服務器-客戶端模式(Server - Client)。在這個架構中,SSH 軟件分成兩個部分:
- 向服務器發出請求的部分,稱為客戶端(client),OpenSSH 的實現為 ssh;
- 接收客戶端發出的請求的部分,稱為服務器(server),OpenSSH 的實現為 sshd。
本教程約定,大寫的 SSH 表示協議,小寫的 ssh 表示客戶端軟件。
另外,OpenSSH 還提供一些輔助工具軟件(比如 ssh-keygen 、ssh-agent)和專門的客戶端工具(比如 scp 和 sftp)
SSH客戶端
1、簡介
OpenSSH 的客戶端是二進制程序 ssh。
1.1 Windows 系統的位置是\Program Files\OpenSSH\bin\ssh.exe
。【Win10中自帶OpenSSH,在設置->應用->可選功能中開啟,安裝后在:C:\Windows\System32\OpenSSH】
利用ssh連接遠程服務器:在windows上cmd,然后ssh 主機用戶@主機ip直接連到遠程,很方便
eg:ssh root@192.168.xx.yy
輸入密碼即可登錄成功。
1.2 Linux 系統一般都自帶 ssh,如果沒有就需要安裝。它在 Linux/Unix 系統的位置是/usr/local/bin/ssh
,
# Ubuntu 和 Debian $ sudo apt install openssh-client # CentOS 和 Fedora $ sudo dnf install openssh-clients
安裝以后,可以使用-V
參數輸出版本號,查看一下是否安裝成功。
$ ssh -V
2、基本用法
ssh 最常見的用途就是登錄服務器,這要求服務器安裝並正在運行 SSH 服務器軟件。
ssh 登錄服務器的命令如下。
$ ssh hostname
上面命令中,hostname
是主機名,它可以是域名,也可能是 IP 地址或局域網內部的主機名。不指定用戶名的情況下,將使用客戶端的當前用戶名,作為遠程服務器的登錄用戶名。如果要指定用戶名,可以采用下面的語法。
$ ssh user@hostname
上面的命令中,用戶名和主機名寫在一起了,之間使用@
分隔。
用戶名也可以使用ssh
的-l
參數指定,這樣的話,用戶名和主機名就不用寫在一起了。
$ ssh -l username host
ssh 默認連接服務器的22端口,-p
參數可以指定其他端口。
$ ssh -p 8821 foo.com
上面命令連接服務器foo.com
的8821端口。
3、連接流程
ssh 連接遠程服務器后,首先有一個驗證過程,驗證遠程服務器是否為陌生地址。
如果是第一次連接某一台服務器,命令行會顯示一段文字,表示不認識這台機器,提醒用戶確認是否需要連接。
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)?
上面這段文字告訴用戶,foo.com
這台服務器的指紋是陌生的,讓用戶選擇是否要繼續連接(輸入 yes 或 no)。
所謂“服務器指紋”,指的是 SSH 服務器公鑰的哈希值。每台 SSH 服務器都有唯一一對密鑰,用於跟客戶端通信,其中公鑰的哈希值就可以用來識別服務器。
下面的命令可以查看某個公鑰的指紋(哈希值)。
$ ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key.pub
256 da:24:43:0b:2e:c1:3f:a1:84:13:92:01:52:b4:84:ff (ECDSA)
上面的例子中,ssh-keygen -l -f
命令會輸出公鑰/etc/ssh/ssh_host_ecdsa_key.pub
的指紋。
ssh 會將本機連接過的所有服務器公鑰的指紋,都儲存在本機的~/.ssh/known_hosts
文件中【windows上位於 C:\Users\用戶名\.ssh ,存的是公鑰】。每次連接服務器時,通過該文件判斷是否為陌生主機(陌生公鑰)。
在上面這段文字后面,輸入yes
,就可以將當前服務器的指紋也儲存在本機~/.ssh/known_hosts
文件中,並顯示下面的提示。以后再連接的時候,就不會再出現警告了。
Warning: Permanently added 'foo.com (192.168.121.111)' (RSA) to the list of known hosts
然后,客戶端就會跟服務器建立連接。接着,ssh 就會要求用戶輸入所要登錄賬戶的密碼。用戶輸入並驗證密碼正確以后,就能登錄遠程服務器的 Shell 了。
之后重新連接就不會提示不認識這台機器了。
4、服務器秘鑰變更
服務器指紋可以防止有人惡意冒充遠程主機。如果服務器的密鑰發生變更(比如重裝了 SSH 服務器),客戶端再次連接時,就會發生公鑰指紋不吻合的情況。這時,客戶端就會中斷連接,並顯示一段警告信息。
這時,你需要確認是什么原因,使得公鑰指紋發生變更,到底是惡意劫持,還是管理員變更了 SSH 服務器公鑰。
5、ssh命令行配置項
-c
-c
參數指定加密算法。
$ ssh -c blowfish,3des server.example.com
# 或者 $ ssh -c blowfish -c 3des server.example.com
上面命令指定使用加密算法blowfish
或3des
。
-C
-C
參數表示壓縮數據傳輸。
$ ssh -C server.example.com
等等...
SSH密鑰登錄
SSH 默認采用密碼登錄,這種方法有很多缺點,簡單的密碼不安全,復雜的密碼不容易記憶,每次手動輸入也很麻煩。密鑰登錄是更好的解決方案。
1、密鑰是什么
密鑰(key)是一個非常大的數字,通過加密算法得到。對稱加密只需要一個密鑰,非對稱加密需要兩個密鑰成對使用,分為公鑰(public key)和私鑰(private key)。
SSH 密鑰登錄采用的是非對稱加密,每個用戶通過自己的密鑰登錄。其中,私鑰必須私密保存,不能泄漏;公鑰則是公開的,可以對外發送。它們的關系是,公鑰和私鑰是一一對應的,每一個私鑰都有且僅有一個對應的公鑰,反之亦然。
如果數據使用公鑰加密,那么只有使用對應的私鑰才能解密,其他密鑰都不行;反過來,如果使用私鑰加密(這個過程一般稱為“簽名”),也只有使用對應的公鑰解密。
2、密鑰登錄的過程
SSH 密鑰登錄分為以下的步驟。
預備步驟,客戶端通過ssh-keygen
生成自己的公鑰和私鑰。
第一步,手動將客戶端的公鑰放入遠程服務器的指定位置。
第二步,客戶端向服務器發起 SSH 登錄的請求。
第三步,服務器收到用戶 SSH 登錄的請求,發送一些隨機數據給用戶,要求用戶證明自己的身份。
第四步,客戶端收到服務器發來的數據,使用私鑰對數據進行簽名,然后再發還給服務器。
第五步,服務器收到客戶端發來的加密簽名后,使用對應的公鑰解密,然后跟原始數據比較。如果一致,就允許用戶登錄。
3、ssh-key
命令:生成密鑰
3.1 基本用法
密鑰登錄時,首先需要生成公鑰和私鑰。OpenSSH 提供了一個工具程序ssh-keygen
命令,用來生成密鑰。
直接輸入ssh-keygen 【注意要用管理員權限登錄 cmd】
,程序會詢問一系列問題,然后生成密鑰。
通常做法是使用-t
參數,指定密鑰的加密算法。
$ ssh-keygen -t dsa
上面示例中,-t
參數用來指定密鑰的加密算法,一般會選擇dsa
算法或rsa
算法。注意,這個參數沒有默認值。
輸入上面的命令以后,ssh-keygen
會要求用戶回答一些問題。
$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_dsa): press ENTER Enter passphrase (empty for no passphrase): ******** Enter same passphrase again: ******** Your identification has been saved in /home/username/.ssh/id_dsa. Your public key has been saved in /home/username/.ssh/id_dsa.pub. The key fingerprint is: 14:ba:06:98:a8:98:ad:27:b5:ce:55:85:ec:64:37:19 username@shell.isp.com
第一個問題,詢問密鑰保存的文件名,默認是~/.ssh/id_dsa
文件,這個是私鑰的文件名,對應的公鑰文件~/.ssh/id_dsa.pub
是自動生成的。用戶的密鑰一般都放在主目錄的.ssh
目錄里面。
如果選擇rsa
算法,生成的密鑰文件默認就會是~/.ssh/id_rsa
(私鑰)和~/.ssh/id_rsa.pub
(公鑰)。
接着,就會是第二個問題,詢問是否要為私鑰文件設定密碼保護(passphrase)。這樣的話,即使入侵者拿到私鑰,還是需要破解密碼。如果為了方便,不想設定密碼保護,可以直接按回車鍵,密碼就會為空。后面還會讓你再輸入一次密碼,兩次輸入必須一致。注意,這里“密碼”的英文單詞是 passphrase,這是為了避免與 Linux 賬戶的密碼單詞 password 混淆,表示這不是用戶系統賬戶的密碼。
最后,就會生成私鑰和公鑰,屏幕上還會給出公鑰的指紋,以及當前的用戶名和主機名作為注釋,用來識別密鑰的來源。
公鑰文件和私鑰文件都是文本文件,可以用文本編輯器看一下它們的內容。公鑰文件的內容類似下面這樣。
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvpB4lUbAaEbh9u6HLig7amsfywD4fqSZq2ikACIUBn3GyRPfeF93l/
weQh702ofXbDydZAKMcDvBJqRhUotQUwqV6HJxqoqPDlPGUUyo8RDIkLUIPRyq
ypZxmK9aCXokFiHoGCXfQ9imUP/w/jfqb9ByDtG97tUJF6nFMP5WzhM= username@shell.isp.com
上面示例中,末尾的username@shell.isp.com
是公鑰的注釋,用來識別不同的公鑰,表示這是哪台主機(shell.isp.com
)的哪個用戶(username
)的公鑰,不是必需項。
下面的命令可以列出用戶所有的公鑰。
$ ls -l ~/.ssh/id_*.pub
生成密鑰以后,建議修改它們的權限,防止其他人讀取。
$ chmod 600 ~/.ssh/id_rsa
$ chmod 600 ~/.ssh/id_rsa.pub
3.2 配置項
ssh-keygen
的命令行配置項,主要有下面這些。
(1)-b
-b
參數指定密鑰的二進制位數。這個參數值越大,密鑰就越不容易破解,但是加密解密的計算開銷也會加大。
一般來說,-b
至少應該是1024
,更安全一些可以設為2048
或者更高。
......
4、手動上傳公鑰
生成密鑰以后,公鑰必須上傳到服務器,才能使用公鑰登錄。
OpenSSH 規定,用戶公鑰保存在服務器的~/.ssh/authorized_keys
文件。你要以哪個用戶的身份登錄到服務器,密鑰就必須保存在該用戶主目錄的~/.ssh/authorized_keys
文件。只要把公鑰添加到這個文件之中,就相當於公鑰上傳到服務器了。每個公鑰占據一行。如果該文件不存在,可以手動創建。
用戶可以手動編輯該文件,把公鑰粘貼進去,也可以在本機計算機上,執行下面的命令。
$ cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
上面示例中,user@host
要替換成你所要登錄的用戶名和主機名。
注意,authorized_keys
文件的權限要設為644
,即只有文件所有者才能寫。如果權限設置不對,SSH 服務器可能會拒絕讀取該文件。
$ chmod 644 ~/.ssh/authorized_keys
【說明:服務器上SSH服務不用重啟】
只要公鑰上傳到服務器,下次登錄時,OpenSSH 就會自動采用密鑰登錄,不再提示輸入密碼。
$ ssh -l username shell.isp.com
Enter passphrase for key '/home/you/.ssh/id_dsa': ************ Last login: Mon Mar 24 02:17:27 2014 from ex.ample.com shell.isp.com>
上面例子中,SSH 客戶端使用私鑰之前,會要求用戶輸入密碼(passphrase),用來解開私鑰。
5、ssh-copy-id 命令:自動上傳公鑰
OpenSSH 自帶一個ssh-copy-id
命令【但是windows上的openssh不自帶,需要另外下載】,可以自動將公鑰拷貝到遠程服務器的~/.ssh/authorized_keys
文件。如果~/.ssh/authorized_keys
文件不存在,ssh-copy-id
命令會自動創建該文件。
用戶在本地計算機執行下面的命令,就可以把本地的公鑰拷貝到服務器。
$ ssh-copy-id -i key_file user@host
上面命令中,-i
參數用來指定公鑰文件,user
是所要登錄的賬戶名,host
是服務器地址。如果省略用戶名,默認為當前的本機用戶名。執行完該命令,公鑰就會拷貝到服務器。
注意,公鑰文件可以不指定路徑和.pub
后綴名,ssh-copy-id
會自動在~/.ssh
目錄里面尋找。
$ ssh-copy-id -i id_rsa user@host
上面命令中,公鑰文件會自動匹配到~/.ssh/id_rsa.pub
。
ssh-copy-id
會采用密碼登錄,系統會提示輸入遠程服務器的密碼。
注意,ssh-copy-id
是直接將公鑰添加到authorized_keys
文件的末尾。如果authorized_keys
文件的末尾不是一個換行符,會導致新的公鑰添加到前一個公鑰的末尾,兩個公鑰連在一起,使得它們都無法生效。所以,如果authorized_keys
文件已經存在,使用ssh-copy-id
命令之前,務必保證authorized_keys
文件的末尾是換行符(假設該文件已經存在)。
6、ssh-agent 命令,ssh-add 命令
私鑰設置了密碼以后,每次使用都必須輸入密碼,有時讓人感覺非常麻煩。比如,連續使用scp
命令遠程拷貝文件時,每次都要求輸入密碼。
ssh-agent
命令就是為了解決這個問題而設計的,它讓用戶在整個 Bash 對話(session)之中,只在第一次使用 SSH 命令時輸入密碼,然后將私鑰保存在內存中,后面都不需要再輸入私鑰的密碼了。
省略...
7、關閉密碼登錄
為了安全性,啟用密鑰登錄之后,最好關閉服務器的密碼登錄。
對於 OpenSSH,具體方法就是打開服務器 sshd 的配置文件/etc/ssh/sshd_config
,將PasswordAuthentication
這一項設為no
。
PasswordAuthentication no
修改配置文件以后,不要忘了重新啟動 sshd,否則不會生效。
SSH服務器
1、簡介
SSH 的架構是服務器/客戶端模式,兩端運行的軟件是不一樣的。OpenSSH 的客戶端軟件是 ssh,服務器軟件是 sshd。本章介紹 sshd 的各種知識。
如果沒有安裝 sshd,可以用下面的命令安裝。
# Debian $ sudo aptitude install openssh-server # Red Hat $ sudo yum install openssh-server
一般來說,sshd 安裝后會跟着系統一起啟動。如果當前 sshd 沒有啟動,可以用下面的命令啟動。
$ sshd
上面的命令運行以后,sshd 自動進入后台,
2、sshd配置文件
sshd 的配置文件在/etc/ssh
目錄,主配置文件是sshd_config
,此外還有一些安裝時生成的密鑰。
/etc/ssh/sshd_config
:配置文件/etc/ssh/ssh_host_ecdsa_key
:ECDSA 私鑰。/etc/ssh/ssh_host_ecdsa_key.pub
:ECDSA 公鑰。/etc/ssh/ssh_host_key
:用於 SSH 1 協議版本的 RSA 私鑰。/etc/ssh/ssh_host_key.pub
:用於 SSH 1 協議版本的 RSA 公鑰。/etc/ssh/ssh_host_rsa_key
:用於 SSH 2 協議版本的 RSA 私鑰。/etc/ssh/ssh_host_rsa_key.pub
:用於 SSH 2 協議版本的 RSA 公鑰。/etc/pam.d/sshd
:PAM 配置文件。
注意,如果重裝 sshd,上面這些密鑰都會重新生成,導致客戶端重新 ssh 連接服務器時,會跳出警告,拒絕連接。為了避免這種情況,可以在重裝 sshd 時,先備份/etc/ssh
目錄,重裝后再恢復這個目錄。
配置文件sshd_config
的格式是,每個命令占據一行。每行都是配置項和對應的值,配置項的大小寫不敏感,與值之間使用空格分隔。
Port 2034
上面的配置命令指定,配置項Port
的值是2034
。Port
寫成port
也可。
配置文件還有另一種格式,就是配置項與值之間有一個等號,等號前后的空格可選。
Port = 2034
注意,注釋只能放在一行的開頭,不能放在一行的結尾。
Port 2034 # 此處不允許注釋
上面的寫法是錯誤的。
修改配置文件以后,可以用 sshd 命令的-t
(test)檢查有沒有語法錯誤。
$ sshd -t
配置文件修改以后,並不會自動生效,必須重新啟動 sshd。
$ sudo systemctl restart sshd.service
3、sshd密鑰
sshd 有自己的一對或多對密鑰。它使用密鑰向客戶端證明自己的身份。所有密鑰都是公鑰和私鑰成對出現,公鑰的文件名一般是私鑰文件名加上后綴.pub
。
DSA 格式的密鑰文件默認為/etc/ssh/ssh_host_dsa_key
(公鑰為ssh_host_dsa_key.pub
),RSA 格式的密鑰為/etc/ssh/ssh_host_rsa_key
(公鑰為ssh_host_rsa_key.pub
)。如果需要支持 SSH 1 協議,則必須有密鑰/etc/ssh/ssh_host_key
。
如果密鑰不是默認文件,那么可以通過配置文件sshd_config
的HostKey
配置項指定。默認密鑰的HostKey
設置如下。
# HostKey for protocol version 1 # HostKey /etc/ssh/ssh_host_key # HostKeys for protocol version 2 # HostKey /etc/ssh/ssh_host_rsa_key # HostKey /etc/ssh/ssh_host_dsa_ke
上面命令前面的#
表示這些行都是注釋,因為這是默認值,有沒有這幾行都一樣。
如果要修改密鑰,就要去掉行首的#
,指定其他密鑰。
HostKey /usr/local/ssh/my_dsa_key HostKey /usr/local/ssh/my_rsa_key HostKey /usr/local/ssh/my_old_ssh1_key
4、sshd 配置項
/etc/ssh/sshd_config
文件里面的配置項,省略......
- PasswordAuthentication
PasswordAuthentication
指定是否允許密碼登錄,默認值為yes
(PasswordAuthentication yes
),建議改成no
(禁止密碼登錄,只允許密鑰登錄)。
- Port
Port
指定 sshd 監聽的端口,即客戶端連接的端口,默認是22(Port 22
)。出於安全考慮,可以改掉這個端口(比如Port 8822
)。
配置文件可以使用多個Port
命令,同時監聽多個端口。
Port 22
Port 80
Port 443
Port 8080
上面的示例表示同時監聽4個端口。
5、sshd 的命令行配置項
sshd 命令有一些配置項。這些配置項在調用時指定,可以覆蓋配置文件的設置。
(1)-d
-d
參數用於顯示 debug 信息。
$ sshd -d
(7)-p
-p
參數指定 sshd 的服務端口。
$ sshd -p 2034
上面命令指定 sshd 在2034
端口啟動。
-p
參數可以指定多個端口。
$ sshd -p 2222 -p 3333
(8)-t
-t
參數檢查配置文件的語法是否正確。
SSH端口轉發
1、簡介
SSH 除了登錄服務器,還有一大用途,就是作為加密通信的中介,充當兩台服務器之間的通信加密跳板,使得原本不加密的通信變成加密通信。這個功能稱為端口轉發(port forwarding),又稱 SSH 隧道(tunnel)。
端口轉發有兩個主要作用:
(1)將不加密的數據放在 SSH 安全連接里面傳輸,使得原本不安全的網絡服務增加了安全性,比如通過端口轉發訪問 Telnet、FTP 等明文服務,數據傳輸就都會加密。
(2)作為數據通信的加密跳板,繞過網絡防火牆。
端口轉發有三種使用方法:動態轉發,本地轉發,遠程轉發。下面逐一介紹。
2、本地轉發
本地轉發(local forwarding)指的是,SSH 服務器作為中介的跳板機,建立本地計算機與特定目標網站之間的加密連接。本地轉發是在本地計算機的 SSH 客戶端建立的轉發規則:它會指定一個本地端口(local-port),所有發向那個端口的請求,都會轉發到 SSH 跳板機(tunnel-host),然后 SSH 跳板機作為中介,將收到的請求發到目標服務器(target-host)的目標端口(target-port)。
$ ssh -L local-port:target-host:target-port tunnel-host
上面命令中,-L
參數表示本地轉發,local-port
是本地端口,target-host
是你想要訪問的目標服務器,target-port
是目標服務器的端口,tunnel-host
是 SSH 跳板機【即 SSH服務器所在的主機, root@ip】。
舉例來說,現在有一台 SSH 跳板機tunnel-host
,我們想要通過這台機器,在本地2021
端口與目標網站www.example.com
的80端口之間建立 SSH 隧道,就可以寫成下面這樣。
$ ssh -L 2021:www.example.com:80 tunnel-host -N
然后,訪問本機的2021
端口,就是訪問www.example.com
的80端口。
$ curl http://localhost:2021 或者在瀏覽器中直接輸入此地址
注意,本地端口轉發采用 HTTP 協議,不用轉成 SOCKS5 協議。
-N
參數,表示不在 SSH 跳板機執行遠程命令,讓 SSH 只充當隧道。另外還有一個-f
參數表示 SSH 連接在后台運行。
采用上面的中介方式,只有本機到 tunnel-host 的這一段是加密的,tunnel-host 到mail.example.com
的這一段並不加密。
解釋:
http://localhost:2021
,數據會發送到本機2021端口,再在本機開一個隨機端口,充當ssh客戶端,再把數據流量發送到22端口的ssh服務端,收到數據以后,解密數據,臨時開一個隨機端口充當客戶端,再把流量發送到80端口hutan.vip
如果經常使用本地轉發,可以將設置寫入 SSH 客戶端的用戶個人配置文件(~/.ssh/config
)。
Host test.example.com
LocalForward client-IP:client-port server-IP:server-port
3、動態轉發
動態轉發指的是,本機與 SSH 服務器之間創建了一個加密連接,然后本機內部針對某個端口的通信,都通過這個加密連接轉發。它的一個使用場景就是,訪問所有外部網站,都通過 SSH 轉發。
動態轉發需要把本地端口綁定到 SSH 服務器。至於 SSH 服務器要去訪問哪一個網站,完全是動態的,取決於原始通信,所以叫做動態轉發。
$ ssh -D local-port tunnel-host -N
上面命令中,-D
表示動態轉發,local-port
是本地端口,tunnel-host
是 SSH 服務器,-N
表示這個 SSH 連接只進行端口轉發,不登錄遠程 Shell,不能執行遠程命令,只能充當隧道。
舉例來說,如果本地端口是2121
,那么動態轉發的命令就是下面這樣。
$ ssh -D 2121 tunnel-host -N
注意,這種轉發采用了 SOCKS5 協議。訪問外部網站時,需要把 HTTP 請求轉成 SOCKS5 協議,才能把本地端口的請求轉發出去。
下面是 SSH 隧道建立后的一個使用實例。
$ curl -x socks5://localhost:2121 http://www.example.com
上面命令中,curl 的-x
參數指定代理服務器,即通過 SOCKS5 協議的本地2121
端口,訪問http://www.example.com
。
如果經常使用動態轉發,可以將設置寫入 SSH 客戶端的用戶個人配置文件(~/.ssh/config
)。
DynamicForward tunnel-host:local-port
SSH證書登錄
SSH 是服務器登錄工具,一般情況下都采用密碼登錄或密鑰登錄。
但是,SSH 還有第三種登錄方法,那就是證書登錄。某些情況下,它是更合理、更安全的登錄方法。
1、非證書登錄的缺點
密碼登錄需要輸入服務器密碼,這非常麻煩,也不安全,存在被暴力破解的風險。
密鑰登錄需要服務器保存用戶的公鑰,也需要用戶保存服務器公鑰的指紋。這對於多用戶、多服務器的大型機構很不方便,如果有員工離職,需要將他的公鑰從每台服務器刪除。
2、證書登錄是什么?
證書登錄就是為了解決上面的缺點而設計的。它引入了一個證書頒發機構(Certificate Authority,簡稱 CA),對信任的服務器頒發服務器證書,對信任的用戶頒發用戶證書。
登錄時,用戶和服務器不需要提前知道彼此的公鑰,只需要交換各自的證書,驗證是否可信即可。
證書登錄的主要優點有兩個:
(1)用戶和服務器不用交換公鑰,這更容易管理,也具有更好的可擴展性。
(2)證書可以設置到期時間,而公鑰沒有到期時間。針對不同的情況,可以設置有效期很短的證書,進一步提高安全性。
3、證書登錄的流程
SSH 證書登錄之前,如果還沒有證書,需要生成證書。具體方法是:
(1)用戶和服務器都將自己的公鑰,發給 CA;
(2)CA 使用服務器公鑰,生成服務器證書,發給服務器;
(3)CA 使用用戶的公鑰,生成用戶證書,發給用戶。
有了證書以后,用戶就可以登錄服務器了。整個過程都是 SSH 自動處理,用戶無感知。
第一步,用戶登錄服務器時,SSH 自動將用戶證書發給服務器。
第二步,服務器檢查用戶證書是否有效,以及是否由可信的 CA 頒發。證實以后,就可以信任用戶。
第三步,SSH 自動將服務器證書發給用戶。
第四步,用戶檢查服務器證書是否有效,以及是否由信任的 CA 頒發。證實以后,就可以信任服務器。
第五步,雙方建立連接,服務器允許用戶登錄。
4、生成 CA 的密鑰
證書登錄的前提是,必須有一個 CA,而 CA 本質上就是一對密鑰,跟其他密鑰沒有不同,CA 就用這對密鑰去簽發證書。
雖然 CA 可以用同一對密鑰簽發用戶證書和服務器證書,但是出於安全性和靈活性,最好用不同的密鑰分別簽發。所以,CA 至少需要兩對密鑰,一對是簽發用戶證書的密鑰,假設叫做user_ca
,另一對是簽發服務器證書的密鑰,假設叫做host_ca
。
使用下面的命令,生成user_ca
。
# 生成 CA 簽發用戶證書的密鑰 $ ssh-keygen -t rsa -b 4096 -f ~/.ssh/user_ca -C user_ca
上面的命令會在~/.ssh
目錄生成一對密鑰:user_ca
(私鑰)和user_ca.pub
(公鑰)。
這個命令的各個參數含義如下。
-t rsa
:指定密鑰算法 RSA。-b 4096
:指定密鑰的位數是4096位。安全性要求不高的場合,這個值可以小一點,但是不應小於1024。-f ~/.ssh/user_ca
:指定生成密鑰的位置和文件名。-C user_ca
:指定密鑰的識別字符串,相當於注釋,可以隨意設置。
使用下面的命令,生成host_ca
。
# 生成 CA 簽發服務器證書的密鑰 $ ssh-keygen -t rsa -b 4096 -f host_ca -C host_ca
上面的命令會在~/.ssh
目錄生成一對密鑰:host_ca
(私鑰)和host_ca.pub
(公鑰)。
現在,~/.ssh
目錄應該至少有四把密鑰。
~/.ssh/user_ca
~/.ssh/user_ca.pub
~/.ssh/host_ca
~/.ssh/host_ca.pub
5、CA 簽發服務器證書
有了 CA 以后,就可以簽發服務器證書了。
簽發證書,除了 CA 的密鑰以外,還需要服務器的公鑰。一般來說,SSH 服務器(通常是sshd
)安裝時,已經生成密鑰/etc/ssh/ssh_host_rsa_key
了。如果沒有的話,可以用下面的命令生成。
$ sudo ssh-keygen -f /etc/ssh/ssh_host_rsa_key -b 4096 -t rsa
上面命令會在/etc/ssh
目錄,生成ssh_host_rsa_key
(私鑰)和ssh_host_rsa_key.pub
(公鑰)。然后,需要把服務器公鑰ssh_host_rsa_key.pub
,復制或上傳到 CA 所在的服務器。
上傳以后,CA 就可以使用密鑰host_ca
為服務器的公鑰ssh_host_rsa_key.pub
簽發服務器證書。
$ ssh-keygen -s host_ca -I host.example.com -h -n host.example.com -V +52w ssh_host_rsa_key.pub
上面的命令會生成服務器證書ssh_host_rsa_key-cert.pub
(服務器公鑰名字加后綴-cert
)。這個命令各個參數的含義如下。
-s
:指定 CA 簽發證書的密鑰。-I
:身份字符串,可以隨便設置,相當於注釋,方便區分證書,將來可以使用這個字符串撤銷證書。-h
:指定該證書是服務器證書,而不是用戶證書。-n host.example.com
:指定服務器的域名,表示證書僅對該域名有效。如果有多個域名,則使用逗號分隔。用戶登錄該域名服務器時,SSH 通過證書的這個值,分辨應該使用哪張證書發給用戶,用來證明服務器的可信性。-V +52w
:指定證書的有效期,這里為52周(一年)。默認情況下,證書是永遠有效的。建議使用該參數指定有效期,並且有效期最好短一點,最長不超過52周。ssh_host_rsa_key.pub
:服務器公鑰。
生成證書以后,可以使用下面的命令,查看證書的細節。
$ ssh-keygen -L -f ssh_host_rsa_key-cert.pub
最后,為證書設置權限。
$ chmod 600 ssh_host_rsa_key-cert.pub
6、CA 簽發用戶證書
下面,再用 CA 簽發用戶證書。這時需要用戶的公鑰,如果沒有的話,客戶端可以用下面的命令生成一對密鑰。
$ ssh-keygen -f ~/.ssh/user_key -b 4096 -t rsa
上面命令會在~/.ssh
目錄,生成user_key
(私鑰)和user_key.pub
(公鑰)。
然后,將用戶公鑰user_key.pub
,上傳或復制到 CA 服務器。接下來,就可以使用 CA 的密鑰user_ca
為用戶公鑰user_key.pub
簽發用戶證書。
$ ssh-keygen -s user_ca -I user@example.com -n user -V +1d user_key.pub
上面的命令會生成用戶證書user_key-cert.pub
(用戶公鑰名字加后綴-cert
)。這個命令各個參數的含義如下。
-s
:指定 CA 簽發證書的密鑰-I
:身份字符串,可以隨便設置,相當於注釋,方便區分證書,將來可以使用這個字符串撤銷證書。-n user
:指定用戶名,表示證書僅對該用戶名有效。如果有多個用戶名,使用逗號分隔。用戶以該用戶名登錄服務器時,SSH 通過這個值,分辨應該使用哪張證書,證明自己的身份,發給服務器。-V +1d
:指定證書的有效期,這里為1天,強制用戶每天都申請一次證書,提高安全性。默認情況下,證書是永遠有效的。user_key.pub
:用戶公鑰。
生成證書以后,可以使用下面的命令,查看證書的細節。
$ ssh-keygen -L -f user_key-cert.pub
最后,為證書設置權限。
$ chmod 600 user_key-cert.pub
7、服務器安裝(服務器)證書
CA 生成服務器證書ssh_host_rsa_key-cert.pub
以后,需要將該證書發回服務器,可以使用下面的scp
命令,將證書拷貝過去。
$ scp ~/.ssh/ssh_host_rsa_key-cert.pub root@host.example.com:/etc/ssh/
然后,將下面一行添加到服務器配置文件/etc/ssh/sshd_config
。
HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub
上面的代碼告訴 sshd,服務器證書是哪一個文件。
重新啟動 sshd。
$ sudo systemctl restart sshd.service
# 或者 $ sudo service sshd restart
8、服務器安裝 CA 公鑰
為了讓服務器信任用戶證書,必須將 CA 簽發用戶證書的公鑰user_ca.pub
,拷貝到服務器。
$ scp ~/.ssh/user_ca.pub root@host.example.com:/etc/ssh/
上面的命令,將 CA 簽發用戶證書的公鑰user_ca.pub
,拷貝到 SSH 服務器的/etc/ssh
目錄。
然后,將下面一行添加到服務器配置文件/etc/ssh/sshd_config
。
TrustedUserCAKeys /etc/ssh/user_ca.pub
上面的做法是將user_ca.pub
加到/etc/ssh/sshd_config
,這會產生全局效果,即服務器的所有賬戶都會信任user_ca
簽發的所有用戶證書。
另一種做法是將user_ca.pub
加到服務器某個賬戶的~/.ssh/authorized_keys
文件,只讓該賬戶信任user_ca
簽發的用戶證書。具體方法是打開~/.ssh/authorized_keys
,追加一行,開頭是@cert-authority principals="..."
,然后后面加上user_ca.pub
的內容,大概是下面這個樣子。
@cert-authority principals="user" ssh-rsa AAAAB3Nz...XNRM1EX2gQ==
上面代碼中,principals="user"
指定用戶登錄的服務器賬戶名,一般就是authorized_keys
文件所在的賬戶。
重新啟動 sshd。
$ sudo systemctl restart sshd.service
# 或者 $ sudo service sshd restart
至此,SSH 服務器已配置為信任user_ca
簽發的證書。
9、客戶端安裝(用戶)證書
客戶端安裝用戶證書很簡單,就是從 CA 將用戶證書user_key-cert.pub
復制到客戶端,與用戶的密鑰user_key
保存在同一個目錄即可。
10、客戶端安裝 CA 公鑰
為了讓客戶端信任服務器證書,必須將 CA 簽發服務器證書的公鑰host_ca.pub
,加到客戶端的/etc/ssh/ssh_known_hosts
文件(全局級別)或者~/.ssh/known_hosts
文件(用戶級別)。
具體做法是打開ssh_known_hosts
或known_hosts
文件,追加一行,開頭為@cert-authority *.example.com
,然后將host_ca.pub
文件的內容(即公鑰)粘貼在后面,大概是下面這個樣子。
@cert-authority *.example.com ssh-rsa AAAAB3Nz...XNRM1EX2gQ==
上面代碼中,*.example.com
是域名的模式匹配,表示只要服務器符合該模式的域名,且簽發服務器證書的 CA 匹配后面給出的公鑰,就都可以信任。如果沒有域名限制,這里可以寫成*
。如果有多個域名模式,可以使用逗號分隔;如果服務器沒有域名,可以用主機名(比如host1,host2,host3
)或者 IP 地址(比如11.12.13.14,21.22.23.24
)。
然后,就可以使用證書,登錄遠程服務器了。
$ ssh -i ~/.ssh/user_key user@host.example.com
上面命令的-i
參數用來指定用戶的密鑰。如果證書與密鑰在同一個目錄,則連接服務器時將自動使用該證書。
11、廢除證書
廢除證書的操作,分成用戶證書的廢除和服務器證書的廢除兩種。
服務器證書的廢除,用戶需要在known_hosts
文件里面,修改或刪除對應的@cert-authority
命令的那一行。
用戶證書的廢除,需要在服務器新建一個/etc/ssh/revoked_keys
文件,然后在配置文件sshd_config
添加一行,內容如下。
RevokedKeys /etc/ssh/revoked_keys
revoked_keys
文件保存不再信任的用戶公鑰,由下面的命令生成。
$ ssh-keygen -kf /etc/ssh/revoked_keys -z 1 ~/.ssh/user1_key.pub
上面命令中,-z
參數用來指定用戶公鑰保存在revoked_keys
文件的哪一行,這個例子是保存在第1行。
如果以后需要廢除其他的用戶公鑰,可以用下面的命令保存在第2行。
$ ssh-keygen -ukf /etc/ssh/revoked_keys -z 2 ~/.ssh/user2_key.pub
SCP命令
scp
是 SSH 提供的一個客戶端程序,用來在兩台主機之間加密傳送文件(即復制文件)。
1、簡介
scp
是 secure copy 的縮寫,相當於cp
命令 + SSH。它的底層是 SSH 協議,默認端口是22,相當於先使用ssh
命令登錄遠程主機,然后再執行拷貝操作。
scp
主要用於以下三種復制操作。
- 本地復制到遠程。
- 遠程復制到本地。
- 兩個遠程系統之間的復制。
使用scp
傳輸數據時,文件和密碼都是加密的,不會泄漏敏感信息。
2、基本語法
scp
的語法類似cp
的語法。
$ scp source destination
上面命令中,source
是文件當前的位置,destination
是文件所要復制到的位置。它們都可以包含用戶名和主機名。
$ scp user@host:foo.txt bar.txt
上面命令將遠程主機(user@host
)用戶主目錄下的foo.txt
,復制為本機當前目錄的bar.txt
。可以看到,主機與文件之間要使用冒號(:
)分隔。
scp
會先用 SSH 登錄到遠程主機,然后在加密連接之中復制文件。客戶端發起連接后,會提示用戶輸入密碼,這部分是跟 SSH 的用法一致的。
用戶名和主機名都是可以省略的。用戶名的默認值是本機的當前用戶名,主機名默認為當前主機。注意,scp
會使用 SSH 客戶端的配置文件.ssh/config
,如果配置文件里面定義了主機的別名,這里也可以使用別名連接。
scp
支持一次復制多個文件。
$ scp source1 source2 destination
上面命令會將source1
和source2
兩個文件,復制到destination
。
注意,如果所要復制的文件,在目標位置已經存在同名文件,scp
會在沒有警告的情況下覆蓋同名文件。
eg:
3、用法示例
(1)本地文件復制到遠程
復制本機文件到遠程系統的用法如下。
# 語法 $ scp SourceFile user@host:directory/TargetFile # 示例 $ scp file.txt remote_username@10.10.0.2:/remote/directory
下面是復制整個目錄的例子。
# 將本機的 documents 目錄拷貝到遠程主機, # 會在遠程主機創建 documents 目錄 $ scp -r documents username@server_ip:/path_to_remote_directory # 將本機整個目錄拷貝到遠程目錄下 $ scp -r localmachine/path_to_the_directory username@server_ip:/path_to_remote_directory/ # 將本機目錄下的所有內容拷貝到遠程目錄下 $ scp -r localmachine/path_to_the_directory/* username@server_ip:/path_to_remote_directory/
(2)遠程文件復制到本地
從遠程主機復制文件到本地的用法如下。
# 語法 $ scp user@host:directory/SourceFile TargetFile # 示例 $ scp remote_username@10.10.0.2:/remote/file.txt /local/directory
下面是復制整個目錄的例子。
# 拷貝一個遠程目錄到本機目錄下 $ scp -r username@server_ip:/path_to_remote_directory local-machine/path_to_the_directory/ # 拷貝遠程目錄下的所有內容,到本機目錄下 $ scp -r username@server_ip:/path_to_remote_directory/* local-machine/path_to_the_directory/ $ scp -r user@host:directory/SourceFolder TargetFolder
(3)兩個遠程系統之間的復制
本機發出指令,從遠程主機 A 拷貝到遠程主機 B 的用法如下。
# 語法 $ scp user@host1:directory/SourceFile user@host2:directory/SourceFile # 示例 $ scp user1@host1.com:/files/file.txt user2@host2.com:/files
系統將提示你輸入兩個遠程帳戶的密碼。數據將直接從一個遠程主機傳輸到另一個遠程主機。
參考:https://wangdoc.com/ssh/index.html