RSA 是一種公鑰加密算法,在 1977 年由麻省理工學院的 Ron Rivest, Adi Shamir, Leonard Adleman 三人一起提出,因此該算法命名以三人姓氏首字母組合而成。
SSH 是 Secure Shell 縮寫,是建立在應用層和傳輸層基礎上的安全協議,為計算機上運行的 Shell 提供安全的傳輸和使用環境。
傳統的 rsh, FTP, POP 和 Telnet 網絡協議因為傳輸時采用明文,很容易受到中間人方式攻擊。為了防止遠程傳輸信息出現泄露,SSH 協議支持對傳輸的數據進行加密,因此它還能防止 DNS 和 IP 欺騙。另外采取 SSH 協議傳輸的數據可以進行壓縮,所以可以加快數據傳輸速度。最初 SSH 協議由芬蘭的 Tatu Ylönen 在 1995 年設計開發,目前屬於 SSH Communications Security 擁有,由於版權原因,1999 年 10 月開源軟件 OpenSSH 被開發出來,它已成為事實上的 SSH 協議標准實現(SSH Communications Security 提供的 SSH 軟件使用不同於 OpenSSH 的私鑰格式),也是目前 Linux 標准配置。
基本框架
SSH 協議主要分成三個協議:
1. 傳輸層協議(The Transport Layer Protocol):傳輸層協議提供服務器認證,數據機密性,信息完整性等支持。
2. 用戶認證協議(The User Authentication Protocol):用戶認證協議為服務器提供客戶端的身份鑒別。
3. 連接協議(The Connection Protocol):連接協議將加密的信息隧道划分成若干邏輯通道,提供給更高層應用協議使用。
驗證方式
SSH 提供兩種安全驗證方式:
1. 基於口令:客戶端使用賬號和口令登錄服務器,所有傳輸數據都會被加密。但可能存在偽造服務器冒充真正的服務器與客戶端進行交互,不能避免中間人攻擊。
2. 基於密鑰:使用一對密鑰(私鑰 + 公鑰),將公鑰放置到服務器注冊。當用戶從客戶端登錄服務器時,服務器會接到使用密鑰(即注冊在服務器的公鑰)進行安全驗證請求,服務器首先比對從客戶端發送過來的公鑰與在己方注冊的公鑰是否一致,如果一致,服務器會使用該公鑰加密數據向客戶端發起 "挑戰"[1],從而避免中間人攻擊。
OpenSSH 提供的工具
OpenSSH 提供了以下幾個工具:
1. ssh:實現 SSH 協議,用以建立安全連接,它替代了較早的 rlogin 和 Telnet。
2. scp, sftp:利用 SSH 協議遠程傳輸文件,它替代了較早的 rcp。
3. sshd:SSH 服務器守護進程,運行在服務器端。
4. ssh-keygen:用以生成 RSA 或 DSA 密鑰對。
5. ssh-agent, ssh-add:管理密鑰的工具。
6. ssh-keyscan:掃描網絡中的主機,記錄找到的公鑰。
生成密鑰對
使用 ssh-keygen 生成一個密鑰對(私鑰 + 公鑰):
$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/xavier/.ssh/id_rsa): id_rsa Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in id_rsa. Your public key has been saved in id_rsa.pub. The key fingerprint is: ce:89:59:3d:a1:3a:99:b3:01:46:78:0f:d1:cc:d4:fa xavier@Qbee-X The key's randomart image is: +--[ RSA 2048]----+ | .=.. | | . .+ . | | . + . . | | o o. o . | | o ..S o | | . . XE. . | | X + | | = | | . | +-----------------+
ssh-keygen 默認使用 RSA 算法,長度為 2048 位,生成一個私鑰文件 id_rsa 和一個公鑰文件 id_rsa.pub,兩個文件默認保存在用戶的 ~/.ssh 目錄下。你可以在命令行交互過程指定密鑰文件路徑,也可以設置密鑰口令,如果設置了密鑰口令,在使用密鑰進行登錄時,需要輸入口令。
ssh-keygen 支持 -f 選項指定密鑰文件路徑,-t 選項指定加密算法,-b 選項指定密鑰長度,-N 選項指定密鑰口令,-C 選項指定注釋。
只要將公鑰文件 id_rsa.pub 提交給服務器,讀取該文件包含的字符串並追加到服務器端用戶的主目錄 ~/.ssh/authorized_keys 文件中,持有私鑰的客戶端就可以使用 SSH 協議登錄服務器了。
SSH 1 協議支持 RSA 算法,SSH 2 協議支持 RSA 和 DSA 兩種算法。ssh-keygen 使用 -t 選項來指明加密算法,rsa1 表示支持 SSH 1,dsa, ecdsa, rsa 表示支持 SSH 2。
生成支持 SSH 1 的 RSA 密鑰:
$ ssh-keygen -t rsa1 -f id-rsa1 Generating public/private rsa1 key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in id-rsa1. Your public key has been saved in id-rsa1.pub. The key fingerprint is: c8:81:8f:dc:cd:ba:86:d2:56:e8:d5:13:3f:57:a5:f9 xavier@Qbee-X The key's randomart image is: +--[RSA1 2048]----+ | | | . .| | . . + | | . = =. + | | o.=.So . . | | . o.o o . E| | o +. . o | | . = .. | | o .. | +-----------------+
從私鑰文件生成公鑰文件:
$ ssh-keygen -y -f id-rsa ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmg/9Hoc98c6AIlEPYK6VqE3ZTlMlfXqn2VgU0NAPXeRmYX+jHYZXA5AxMNTD8KgZIuilK23qzzKBy0hgoO9DDpsBg98Pf4NLkHjTcjpPFX1TBD6RWO/OX/g4uN+gZH1/zoREJa4fit8SSG2V2GoQkqrhfRYCy+a9mQX29ZvOLfYK/aMVjb+yfzLJychdvV3CQkDvkd5R/DHNU6ZQ3pyIEjA/cUQqqmgxQj0f72y8IXv8zesXtjXaaKG17R2oSN1MNDZo/y4m426MYxl4mMQMvM5yR3UvhD93pgNgaR8LY/vspcIeE6cJZsGl21oYtrDZ/GdmF5ulMGwjIDfTJRLvb
修改私鑰文件的注釋和口令(僅支持 RSA1,如果原 RSA1 文件含有注釋或口令,才會提示修改相應的注釋或口令。):
$ ssh-keygen -c Enter file in which the key is (/home/xavier/.ssh/id_rsa): id-rsa1 Key now has comment 'Hello' Enter new comment: HelloWorld The comment in your key file has been changed.
修改私鑰文件口令(命令:ssh-keygen -p [-P old_password] [-N new_password] [-f keyfile]):
$ ssh-keygen -p -f id-rsa Key has comment 'id-rsa' Enter new passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved with the new passphrase.
如果想要取消口令,只需要在輸入密碼為空即可。私鑰口令只是對私鑰文件的訪問權限,修改和刪除口令並不影響私鑰內容。
公鑰指紋
由於公鑰長度一般都是 1024 或 2048 個字節,不方便進行比對,因此通常使用一個較短的字符串來代表它,這個就是公鑰指紋。公鑰指紋的計算方法一般就是對公鑰字符串進行 MD5 或者 SHA-1 等摘要計算得到,一個 1024 字節長度的 RSA 算法公鑰,經過指紋計算后得到的公鑰指紋只有 128(MD5摘要)字節或者 160(SHA-1)字節。
你可以使用 ssh-keygen 工具來計算公鑰指紋:
$ ssh-keygen -l -f id_rsa.pub 2048 ce:89:59:3d:a1:3a:99:b3:01:46:78:0f:d1:cc:d4:fa xavier@Qbee-X (RSA)
如果客戶端是第一次訪問服務器,系統會提示以下信息:
$ ssh xavier@192.168.1.5 The authenticity of host '192.168.1.5 (192.168.1.5)' can't be established. RSA key fingerprint is 1c:bb:f1:e5:40:34:75:d3:37:b7:8f:b3:4a:6f:b6:47. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.1.5' (RSA) to the list of known hosts.
這是因為客戶端第一次連接目標服務器,客戶端沒有目標服務器的公鑰存根,因此系統告訴你目前正在連接的服務器所使用的公鑰指紋(公鑰指紋代表着公鑰,但長度較短便於識別),需要你看看這個指紋是否正確,如果正確就正式建立連接,如果指紋可疑就不要建立連接。
這個公鑰指紋是基於服務器的公鑰計算而來,服務器的公鑰一般保存在 /etc/ssh/ssh_host_rsa_key.pub 文件中。如果你事先知道服務器公鑰,那么你自然可以輕松識別指紋並決定是否建立連接,但如果是在互聯網中連接陌生服務器,你並知道目標服務器的公鑰,這樣就無法識別當前指紋是不是惡意的中間人服務器提供的,為了解決這個問題,服務器端管理員需要提前公示自己的公鑰,或者是從證書機構申請證書,用戶只要使用公示的公鑰,或者去頒證機構認證下載證書就可以識別當前連接的服務器是否是虛假的中間人。
一旦你確認指紋合法性並建立連接后,客戶端就會將服務器的公鑰保存在 $HOME/.ssh/known_hosts 文件中,下次連接時系統自動將對方發過來的公鑰與已知公鑰進行比對,如果正確就直接建立連接,如果不正確將給出警告提示說公鑰不匹配並阻止建立連接。
當由於公鑰不匹配而無法建立連接時,可能有幾個原因,一是目標服務器更換了公鑰;二是目標服務器更換了 IP 地址或者域名,導致你連接到其他主機致使公鑰不匹配;三是有惡意攻擊者截斷了連接,正在使用偽造的主機地址試圖欺騙你建立連接。無論是哪個原因,你都應該保持警惕,謹慎建立連接。
注:
[1] "挑戰" 是指服務器使用公鑰加密數據發送給客戶端,客戶端使用配對的私鑰對數據進行解密,客戶端成功解密后將答案發回服務器進行驗證,結果一致則挑戰成功,表示客戶端是合法用戶可以進行安全通信。
附:
1. RSA 算法