本文為技術入門普及文,為方便閱讀,以下名詞將在首次出現時同時標示中英文,之後統一以中文描述。
讀者如果有不熟悉的名詞可以透過下列此表進行比對、確認說明。
類別 | 名詞 | 中文名稱 | 說明 |
---|---|---|---|
協定與標準 | SSH(Secure Shell) | 安全殼層協定 | 一種提供安全遠端連線的網路協定。 |
OpenSSH | 開源 SSH 實作 | Linux 與 Windows 系統常見的 SSH 軟體。 | |
RFC 4253 / RFC 4252 / RFC 4254 | SSH 標準規範 | 定義 SSH 傳輸層、認證層與連線層協定。 | |
IETF(Internet Engineering Task Force) | 網際網路工程任務組 | 制定並維護網路標準的組織。 | |
連線角色 | Client | 用戶端 | 發起 SSH 連線的主機。 |
Server | 伺服器端 | 接收並處理 SSH 請求的主機。 | |
SSH 登入五階段 | 版本號協商(Version Exchange) | — | 確認雙方支援的 SSH 版本。 |
演算法與金鑰交換(Algorithm Negotiation + Key Exchange) | — | 協商加密與驗證演算法,生成會話金鑰。 | |
使用者身分驗證(User Authentication) | — | 驗證使用者合法性(密碼或金鑰)。 | |
會話請求(Channel Request) | — | 建立會話通道,準備執行命令或開啟 shell。 | |
資料交換(Data Exchange) | — | 雙向傳輸與加密解密資料。 | |
加密與演算法 | Diffie-Hellman 金鑰交換 | — | 一種主流的建立共享密鑰的演算法。 |
金鑰交換演算法(Key Exchange Algorithm) | — | 用於產生臨時會話金鑰。 | |
加密演算法(Encryption Algorithm) | — | 對傳輸資料加密。 | |
封包驗證演算法(MAC, Message Authentication Code) | — | 確保封包內容未被竄改。 | |
壓縮演算法(Compression Algorithm) | — | 減少資料傳輸量。 | |
會話與金鑰 | 會話金鑰(Session Key) | — | 雙方共用,用於加密通訊內容。 |
會話識別碼(Session ID) | — | 標識此次 SSH 連線,防止重放攻擊。 | |
共享密鑰(Shared Secret) | — | Diffie-Hellman 計算所得的共同密鑰。 | |
驗證與金鑰管理 | 密碼驗證(Password Authentication) | — | 使用帳號密碼登入。 |
公鑰驗證(Public Key Authentication) | — | 以非對稱加密進行登入驗證。 | |
ssh-keygen | — | 生成公鑰與私鑰的工具。 | |
公鑰(Public Key) | — | 用於驗證簽章。 | |
私鑰(Private Key) | — | 用於簽章,不可外傳。 | |
authorized_keys | — | 伺服器端紀錄授權登入公鑰的檔案。 | |
~/.ssh/ | — | 儲存金鑰與設定檔的目錄。 | |
封包與控制訊息 | CHANNEL_OPEN_CONFIRMATION | — | 伺服器回覆通道開啟成功。 |
CHANNEL_OPEN_FAILURE | — | 伺服器回覆通道開啟失敗。 |
本文主要參考 https://www.cdxy.me/?p=394
網路上有很多關於 SSH (安全殼層協定)的說明文章,但我只找到這篇不會有各種專有名詞滿天飛,敘述簡單清晰,是比較好懂的一篇文章,在 SSH 的了解上對我幫助極大,推薦給大家。
雖然說是這樣說,但還是有很多專有名詞,為了降低閱讀難度,我在上面整理了一張表,請讀者眼花撩亂了就看一眼這張表吧,多少會有幫助。
直接進入主題。
問題與五階段
- SSH 從發出請求到連線、能夠傳輸,中間到底經過了什麼?
- 我準備好了金鑰(Key Pair),也能順利連線,但 SSH 是怎麼驗證的?
- 做為一個以安全性為主要賣點的連線方式,它到底如何保障傳輸的安全性?
這篇文章要來嘗試解答這些問題,主要說明 SSH 整個連線會經過的過程
首先,SSH 從發出請求到連線、能夠傳輸,可分為五個階段:
- Version Exchange 版本號協商
- Algorithm Negotiation + Key Exchange 密鑰與演算法協商
- User Authentication 使用者身分驗證
- Channel Request 會話請求
- Data Exchange 會話交換
💡 補充:
上面五個階段依據 SSH 協定系列(RFC 4253、RFC 4252、RFC 4254)而來。
SSH 協定系列 是由 IETF(Internet Engineering Task Force) 定義。
OpenSSH ⇒ 目前主流的 SSH 連線軟體,在 Linux 和 Windows 系統上廣泛使用。
一、版本號協商(Version Exchange)
進入到第一個階段,以順序排序,雙方會有以下動作:
- 用戶端 Client 向 伺服器端 Server 發起 SSH 連線。 → 對伺服器端的 port 22 發送連線請求。
- 伺服器端傳送自己的版本號給用戶端。 例如:
SSH-2.0-OpenSSH_9.6
- 用戶端傳回自己的版本號。 例如:
SSH-2.0-OpenSSH_9.4
- 雙方比對版本是否相容。 若能相容 → 進入下一階段; 若不相容 → 結束連線。
💡 補充:
- 一般來說,SSH 連線預設會使用 port 22,但不是必須得用 port 22。
- 理論上不會出現「用戶端說相容、伺服器端說不相容」的狀況,若真的不同(例如伺服器端只支援 SSH-1.5),用戶端一收到就直接斷線
二、密鑰與演算法協商(Algorithm Negotiation + Key Exchange)
當連線建立後,用戶端與伺服器端會交換各自支援的算法清單,並從中挑出雙方都能理解的一組組合。
在這個階段,最重要的是雙方會生成:
- Session Key( 會話金鑰) → 用戶端與伺服器端各自透過 Diffie-Hellman 算法,共同算出一把只有他們知道的共享秘鑰(shared secret)。
(不一定是 Diffie–Hellman,只是它比較常見)
這把會話金鑰後續會被用來:- 加密傳輸資料
- 驗證封包完整性(MAC)
注意:這個金鑰是「暫時」的,每次重新連線都會重新算一次。
- Session ID(會話 ID) →標識整個 SSH session (SSH 會話)(就像一張身分證)。
💡 補充:
- 每次協商(Negotiation)雙方都會確定出三大類算法
類別 | 功能 | 範例 | 用途階段 |
---|---|---|---|
① 金鑰交換算法 (Key Exchange Algorithm) | 決定雙方如何一起產生臨時的「共同密鑰 (session key)」 | diffie-hellman-group14-sha256 、curve25519-sha256 | 建立安全通道時使用 |
② 加密算法 (Encryption / Cipher) | 負責如何加密後續傳輸的資料(使用上一步產生的 session key) | aes128-ctr 、aes256-ctr 、chacha20-poly1305 | 對封包內容加密 |
③ 封包驗證算法 (MAC / Message Authentication Code) | 驗證封包內容是否被竄改,確保完整性 | hmac-sha2-256 、hmac-sha1 | 對每個封包附加驗證碼 |
- 「shared secret」不是 session key,其只是生成 session key 的中間值,可以這樣理解:
shared secret = 後續「衍生出 session key」的基礎材料
三、使用者身分驗證 User Authentication
結束上個階段,此時已有會話密鑰與會話 ID,後續所有資料皆使用該密鑰加密傳輸。
SSH 允許多種驗證方式,主要是:
- 帳號及密碼驗證
- 公鑰私鑰驗證
帳號密碼驗證
流程如下:
- 用戶端準備登入資訊: 包含使用者名稱、欲採用的驗證方式、密碼等。
- 用戶端使用前一階段產生的 會話密鑰 將這些資料加密後發送給伺服器端。
- 伺服器端收到後,用相同的 會話密鑰 解密封包,取得帳號與密碼。
- 伺服器端檢查帳號是否存在,密碼是否正確(例如查
/etc/shadow
或 PAM 模組)。 - 若驗證通過 → 登入成功;若錯誤 → 拒絕連線。
公鑰私鑰驗證
這裡我自己會分為兩個流程:準備、實際驗證。
準備流程:
- 使用指令
ssh-keygen
生成一對金鑰檔案:- 公鑰:id_dsa.pub
- 私鑰:id_dsa
- 將公鑰放置於伺服器上對應帳號的
.ssh
目錄下的authorized_keys
- 將私鑰放置於 用戶端,用於證明身分,不可外傳
實際驗證流程:
- 用戶端發送要操作的伺服器端使用者及公鑰資訊(以 Session key 加密) 用戶端對伺服器端說:「我要以某個使用者身分登入,並使用這把公鑰驗證。」
- 伺服器去 authorized_keys 查找該使用者的公鑰
- 若存在 → 發 challenge 給你(下一階段)。 找不到 → 直接回「Permission denied (publickey)」。
💡 補充:
.ssh/
是儲存 SSH 設定與金鑰的目錄 裡面可以包含多種檔案,例如:authorized_keys
authorized_keys
是一個純文字檔案,每一行代表一個允許登入該帳號的公鑰內容。- 使用公鑰私鑰驗證登入時,用戶端用私鑰簽名,伺服器端用公鑰驗證。
動作 ⇒ 伺服器端提供要簽的內容、用戶端對資料簽章。 - 如果 .ssh 或是 authorized_keys 權限太開放,同樣拒絕登入(不夠安全)
四、會話請求 Channel Request
當使用者身分驗證成功後,SSH 進入「建立會話通道(Channel)」的階段。
這個階段主要讓用戶端告訴伺服器端:
「我現在想開一個通道,用來執行某個動作(例如開 shell、執行指令、傳檔案等)。」
若請求成功 ⇒ 伺服器回覆 CHANNEL_OPEN_CONFIRMATION
若失敗 ⇒ 回覆 CHANNEL_OPEN_FAILURE
五、會話交換 Data Exchange
然後就可以進行雙向資料傳輸了,流程如下:
- 用戶端將要執行的命令(或輸入的操作)加密後傳給伺服器端。
每一個封包都會經由前面建立的 Session key 加密與簽章驗證(MAC)。
- 伺服器端收到後,用 Session key 解密並執行指令。
可能是開啟 shell、執行單一命令、或傳送檔案。
- 伺服器端將執行結果加密回傳給用戶端。
- 用戶端解密後顯示在終端機上。
耍!
發佈留言