從 Windows 使用金鑰免密碼登入 SSH/SFTP/SCP
2 |
很早之前我就知道 SSH 可以用金鑰取代密碼,免敲密碼登入遠端主機。不知為何,我老覺得花心力研究太麻煩,加上擔心金鑰被偷等同破防更不安全,寧可乖乖敲密碼。偏偏我密碼又喜歡設長一點確保強度,便抱著鴕鳥心態不知不覺多敲了幾百次密碼,耗費時間與力氣早超過學習成本。為什麼會逃避這麼久?自己都覺好笑。
昨天剛好研究到 Windows OpenSSH Server,今天打鐵趁熱,了結一椿心事。
試了一下,新版 Windows 10 及 Windows 11 都內建了 OpenSSH Client,不需手動安裝:
換言之,在 Windows 10/11 直接開啟 CMD 或 PowerShell 視窗敲 ssh CLI 指令就能用。若作業系統預設未安裝,可參考官方文件:在 Windows安裝 OpenSSH 客戶端)
先簡單說說 SSH 金鑰認證概念,第一步要在客戶端建立一對金鑰,私密金鑰只保存在客戶端,需嚴密保管不可外洩;公開金鑰則對外公開,用來驗證數位簽章的有效性。接著,我們將公鑰部署到遠端主機,設成己授權的對象,之後當用 SSH 連上遠端主機,客戶端會用私鑰產生數位簽章,伺服器端則用事先登記的公鑰驗證簽章真偽,以此完成登入驗證。
坊間的 SSH 金鑰登入教學多以 Linux 為主,Winows 的話,當然是看本草綱目:Key-based authentication in OpenSSH for Windows。
OpenSSH Client 內建金鑰產生工具 - ssh-keygen,金鑰有多種規格,包含 DSA, RSA, ECDSA, or Ed25519,預設是用 RSA,但如果不用相容老舊系統,建議使用安全強度較高的 Ed25519。(參考:選擇 SSH key 的加密演算法 by Chris Yuan
指令 ssh-keygen -t ed25519
可用來產生一對 Ed25519 公私鑰:
產生的金鑰檔預設儲存在 %UserProfile%\.ssh 目錄,id_ed25519 是私鑰檔,需比照密碼嚴加保護,被偷走身分即會被冒用;而 id_ed25519.pub 則是公鑰可公開散佈,提供給溝通對象證驗我們的身分。
假設我有一台 Linux,想免密碼登入為 jeffrey,則我要將 id_ed25519.pub 的內容加入 /home/jeffrey/.ssh/authorized_keys 檔案,該檔案可包含多筆公鑰資料允許多個客戶端用金鑰登入,內容範例如下:
在 authorized_keys 加入公鑰後,馬上就能免密碼登入囉! (原來這麼簡單,搞不懂我為什麼拖了這麼久)
如果登入的對象是 Windows OpenSSH Server,做法類似,差別在於 authorized_keys 位置不同,一般使用者位於 $env:USERPROFILE\.ssh\authorized_keys
參考,而建立 Azure VM 時新增的使用者其實是內建管理者,則要寫入 $env:ProgramData\ssh\administrators_authorized_keys
參考,原本沒注意到,在這裡卡了一陣子。
到這裡我們已順利實現免密碼 SSH 登入,但有個風險:私鑰檔放在 $env:USERPROFILE\.ssh
目錄,可能會被駭客鎖定設法偷走;而為了免敲密碼,ssh-keygen 產生金鑰時沒設密碼,任何拿到私鑰檔的人都能使用,少了一層保護。
Windows 在安裝 OpenSSH 客戶端時會一併安裝 sshd-agent 服務 (OpenSSH Authentication Agent),負責保管私密金鑰並在 SSH 連線時協助認證身分。sshd-agent 預設為停用狀態,若打算長期使用金鑰免密碼登入 SSH,需用管理者身分執行以下 PowerShell 指令啟用服務:
# 改為開機自動啟動
Get-Service ssh-agent | Set-Service -StartupType Automatic
# 現在啟用服務方便後續測試
Start-Service ssh-agent
接著用 ssh-add $env:USERPROFILE\.ssh\id_ed25519
將私鑰交給 sshd-agent 保管,之後便可將 id_ed25519 備份到安全的地方並從本機移除。由於交給 sshd-agent 保管的金鑰無法再被取出來,而本機上私鑰檔也被刪除,私鑰檔外流的風險大幅降低。另外,若配合 ssh-agent 使用,ssh-keygen 時建議設定密碼,ssh-add 輸入密碼匯入,之後登入不需再輸入;而有了密碼保護,即使私鑰檔遭竊,至少還有第二層防護,在我心中是更安全的做法。
但要提醒,私鑰檔需妥善保存,密碼也需記好,一旦遺失檔案或忘記密碼,只能重新產生並逐一更新登入對象的 authorized_keys 資料。
【小結】
拖了這麼久,今天總算學會在 Windows 使用金鑰登入 SSH 的做法。我歸納出的理想 SOP 是:用 ssh-keygen -t ed25519 產生具密碼保護的金鑰,用 ssh-add 將金鑰匯入 ssh-agent 後將 id_ed25519 私鑰檔自 Windows 移除妥善保存在其他地方(然後密碼也要記好),應是兼顧安全與方便的做法。而如果你不嫌麻煩,還可用金鑰並每次輸入密碼,將是更安全的做法。方便與安全如何權衡,大家自行拿捏。
Comments
# by kaede
感謝大神,節省了調查的時間 一樣卡在 administrators_authorized_keys 的問題上
# by CHEN
Server要求公鑰須為RSA TYPE,結果C#使用Renci.SshNet連線只能接受 Ed25519,好煩呀!