SSH 全名是 Secure Shell (安全外殼協定),是一種加密的網路傳輸協定,可以在不安全的網路中提供安全的網路傳輸環境。SSH 透過在使用者和客戶端之間建立一條安全的隧道來實現連接,並進行資料的傳輸。SSH 現今最常被使用的是進行遠端連線執行命令。
加密方式
SSH 採用 Public-key cryptography
來為資料進行加解密,每一個使用者都會有兩把鑰匙 (key) :
- 公鑰 (public key) : 任何人都可以看到公鑰的內容,主要用於加密。
- 私鑰 (private key) : 私鑰只有擁有者自己擁有不會傳給別人,主要用於解密和數位簽章。
通過公鑰將資料進行加密後,可以很輕易的用私鑰解密,而如果想要用公鑰來猜私鑰就會非常困難。這就是所謂的 非對稱式加密
,透過不同的兩把鑰匙來分別作加解密,又因為私鑰握在自己手上所以不用擔心在傳輸過程中被攔截。
數位簽章
前面提到公鑰是任何人都可以看到的,那這樣每個人都可以用這把公鑰將資料加密再傳給同一個人,這樣要如何確定這封訊息是誰傳給我的 ? 是否是偽造的訊息呢 ?
因此數位簽章的概念是先將資料透過雜湊函數產生雜湊值,接著再用自己的私鑰將雜湊值加密,並且連同原本加密的資料一起傳送。產生雜湊值的動作是單向的,所以不用擔心會被反向破解出原本的資料。
當對方收到加密資料和數位簽章之後就可以用我的公鑰解出雜湊值,接著再用他自己的私鑰解出加密的資料。此時再將解密後的資料透過雜湊函數產生雜湊值,並和數位簽章解出的雜湊值進行比對,如果一樣則代表這則訊息是我本人傳送的。
運作流程
- 在進行資料傳輸前, A 和 B 雙方都要先生成一組公私鑰。
- 將公鑰傳給對方,此時 A 有自己的私鑰和 B 的公鑰,B 有自己的私鑰和 A 的公鑰。
- 現在當 A 要傳資料給 B 就用 B 的公鑰將資料加密,並且用 A 自己的私鑰將資料進行數位簽章,接著將加密資料和數位簽章一起傳給 B。
- 當 B 收到後先透過 A 的公鑰解出數位簽章,接著再用 B 自己的私鑰解出加密的資料。
- 比對數位簽章的雜湊值和解密的資料經過雜湊函數所產生的雜湊值是否相同即可確認資料的真實性。
中間人攻擊 (Man-in-the-middle attack)
雖然看起來上述加了數位簽章之後安全性已經提高了許多,但是公鑰在傳輸的過程中如果在中途被駭客攔截,那駭客就可以發送一組假的公鑰給對方並且解開資料進行偽造。如下 :
- A 生成了一組公私鑰,並且準備將公鑰傳送給 B。
- A 傳送的過程中被駭客 H 在中途攔截,此時駭客 H 就再生成了一組
公私鑰 (pubH1、priH1)
並將這組假的公鑰 (pubH1)
傳送給 B。而 B 就以為pubH1
是 A 的公鑰。 - 同樣 B 生成公私鑰後要傳送公鑰給 A 時在中途被駭客 H 攔截,駭客 H 就再生成了一組
公私鑰 (pubH2、priH2)
並將這組假的公鑰 (pubH2)
傳送給 A。而 A 就以為pubH2
是 B 的公鑰。 - 現在當 A 要傳送訊息時用了
假的 B 公鑰 (pubH2)
加密資料再用 A 自己的私鑰加密數位簽章,接著準備傳送給 B。 - 傳送過程中被駭客 H 在中途攔截,此時資料因為是用
pubH2
加密,而駭客 H 因為擁有priH2
所以就可以將加密的資料進行解密。 - 此時駭客 H 就可以任意更改資料內容,並且再用
B 的公鑰
將資料進行加密,接著透過priH1
這組私鑰進行數位簽章,最後就可以將這組偽造的資料傳送給 B。 - 當 B 收到加密的資料和數位簽章時,會先用自己的私鑰將資料進行解密,這部分是沒有問題的因為駭客 H 是用
B 的公鑰
進行加密。接著 B 會再用他以為是 A 的公鑰的pubH1
解出數位簽章,最後比對結果吻合就認定是 A 傳送的訊息。
第三方認證公鑰
非對稱式協議唯一會產生的問題就是交換公鑰時有可能被偷換過,不過解法其實也很簡單,就是透過一個可信的第三方服務來認證拿到的公鑰是不是真的,這樣就可以確定公鑰有沒有問題。
基本操作方式
如果要使用 SSH 連線到另一台 Linux 伺服器,可以透過 SSH 指令進行連接,如下 :
1 | ssh [user]@[host] |
user : 要登入的帳號名稱。
host : 遠端主機的名稱或 IP 位址。
登入時預設要使用帳號的密碼進行認證才能登入。
範例
下面這個範例是要連線到 192.168.0.100
這個 IP 位址的主機並且用 tony
這個帳號進行登入。
1 | $ ssh tony@192.168.0.100 |
而如果本機的使用者帳號和遠端登入的是同一個帳號名稱則可以不需要指定 user
,如下 :
1 | tony@mycomputer$ ssh 192.168.0.100 |
Port
SSH 預設是使用 Port 22
,但是不一定要使用 22
,是可以更改的。許多的伺服器因為安全性因素會改用其他 Port。更改過 Port 會比較安全,預設的 22
因為大家都知道,所以必然是成為駭客首先攻擊的目標。
若不是使用預設的 22
作為 SSH 的 Port,則可以使用 -p
來指定。
1 | ssh -p [port number] [user]@[host] |
範例
下面這個範例是已經將 Port 從預設的 22
切換到了 2022
,這樣就可以透過 2022
來連線。
1 | ssh -p 2022 tony@192.168.0.100 |
更改 Port 的方式請參考 CentOS/Debian/Ubuntu Linux修改SSH默認22端口。
遠端執行指令
如果只是要執行一個指令的話不一定要登入伺服器再執行,可以將指令放在 ssh 指令末端就可以直接執行,執行完後會自動離開。
1 | ssh [user]@[host] [command] |
範例
這個範例首先先遠端建立一個檔案,就著再次用遠端執行的方式列出來看剛才建好的檔案。
1 | $ ssh tony@192.168.0.100 touch test.txt |
除錯模式
在 SSH 連線時可以加上 -v
開啟除錯模式就會輸出詳細的偵錯訊息。
1 | ssh -v [user]@[host] |
範例
這個範例我們加上 -v
開啟除錯模式,可以看到會輸出許多的偵錯訊息,就可以利用這些訊息來進行除錯。
1 | $ ssh -v tony@192.168.0.100 |
免密碼登入
前面有介紹了公私鑰的概念,但是預設登入時還是需要輸入帳號的密碼來驗證。實際上也是可以建立一組公私鑰來代替密碼進行登入,而且只要第一次驗證過了以後就不需要再輸密碼就可以自動驗證並登入。
建立公私鑰
要建立一組新的公私鑰可以透過 ssh-keygen
指令完成。
1 | ssh-keygen |
建立好的公私鑰如果沒有特別指定會放在 /home/[user]/.ssh
目錄下,並命名為 id_rsa
和 id_rsa.pub
,分別是私鑰和公鑰。
如果不放心還是希望要輸入一些認證資訊的話可以在 passphrase
指定,則連線時就要輸入指定的 passphrase
才能登入。
範例
下面就直接建立了一組公私鑰,在第三行可以指定建立好的公私鑰要放在哪,在第五行的地方可以指定 passphrase
。如果都不指定就直接按 Enter
略過。
1 | $ ssh-keygen |
下面分別就是產生出來的私鑰和公鑰,格式就長這樣,內容有稍微調整過了所以不要直接拿去用會沒有用。請自己建一組出來。
1 | $ cat id_rsa |
複製公鑰到被連線主機
scp
指令可以遠端加密複製檔案或目錄。這裡就不詳述 scp
指令的用法,下面的指令是將剛剛建立好的公鑰 ~/.ssh/id_rsa.pub
複製到 192.168.0.100
這台主機的 tony
這個使用者下的 ~/.ssh/
這個目錄。
1 | $ scp ~/.ssh/id_rsa.pub tony@192.168.0.100:~/.ssh/ |
將公鑰寫入 authorized_keys
Linux 系統預設放置公鑰的檔案是 authorized_keys
,所以要先登入到遠端的主機或是使用遠端執行命令將公鑰寫入到 authorized_keys
。
1 | $ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys |
更改 authorized_keys 的權限
如果是之前沒設定過 authorized_keys
的權限或是第一次加入公鑰到遠端主機的話都要設定 authorized_keys
的權限,若是權限太大則 ssh
會判斷金鑰不安全而不能使用。這裡我們設定自己可以讀寫即可。
1 | $ chmod 600 ~/.ssh/authorized_keys |
重新登入
至此再重新登入就可以不需要密碼了,如果還有遇到金鑰權限的問題可以先檢查一下本機的 id_rsa
和 id_rsa.pub
權限是否過大,可以設定為自己可讀寫就好。
1 | chmod 600 ~/.ssh/id_rsa.pub |
使用別名登入
從前面介紹的 SSH 連線方式可以看到,每次連線都要輸入帳號和 Server 的 IP 位址,但是如果有多台 Server 要連就可能會記不住。因此可以在 ~/.ssh
目錄下的 config
檔加入一些設定,以後就可以只用別名來進行連線。設定的內容如下 :
1 | Host [alias] |
Host : 可以自行設定想要的別名,之後就會用這個名稱進行連線,所以建議是直接用 Server 的名稱。
HostName : 填入 Server 的 IP。
Port : ssh 預設的 Port 是 22,如果你的系統有更改過這裡就需要再特別設定。
User : 要登入的使用者帳號名稱。
設定完成後就可以直接指定別名 (Host) 來進行登入,如下 :
1 | ssh [alias] |
而原本不指定用別名連線的方式就可以對應出如下的格式 :
1 | ssh [user name]@[IP address] |
範例
首先要先在 ~/.ssh/config
中加入 Server 的設定,如果 ~/.ssh/config
不存在,那就建立一個,如下 :
1 | $ cat > config |
設定完成後就可以直接指定別名進行登入,如下 :
1 | $ ssh srv1 |
遠端主機的公鑰
在前面介紹 SSH 資料傳輸時會將公鑰傳給對方,而使用遠端連線登入時,遠端的主機同樣也會將他的公鑰傳到我們的本機上。儲存的位置就在 ~/.ssh/known_hosts
這個檔案裡。如下 :
1 | $ cat ~/.ssh/known_hosts |
所以當遠端主機重新設定公鑰或者是重灌系統的話,公鑰就會和本機上的不一樣,造成驗證失敗。這時只要將 known_hosts
這個檔案刪除讓 ssh
重新連線就會自動抓取再寫到 known_hosts
。
不過如果刪除 known_hosts
的話就變成所有遠端主機的公鑰都要重新抓一次,所以如果不希望這樣的話也可以打開 known_hosts
直接刪除對應主機的那一行設定即可。
Summary
本篇介紹了 SSH 的原理即使用方式,大部分的情況都是用在遠端登入來進行操控。此外加入了免密碼登入和使用別名登入的功能也可以讓我們更方便的進行連線。
參考
[1] 小技巧:實現ssh服務器别名免密碼登錄
[2] 網路安全(1) - 基礎密碼學
[3] ssh公鑰私鑰認證原理
[4] 你該知道所有關於 SSH 的那些事
[5] CentOS/Debian/Ubuntu Linux修改SSH默認22端口
[6] Linux 的 scp 指令用法教學與範例:遠端加密複製檔案與目錄