The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何在 Windows 架設高安全性的 SFTP (SSH File Transfer Protocol) 伺服器

延續的我前一天的 如何在 Windows 正確的安裝與設定 OpenSSH Server 服務 文章,在 Windows 平台架設 OpenSSH Server 搭配 SFTP 就能進行安全的檔案傳輸,防火牆也只需要開啟 Port 22 而已,清楚明瞭,系統配置預設也非常安全。這篇文章我就來分享如何對 SFTP 進行安全的設定,讓你在遠端檔案傳輸時能夠更加安全。

設定金鑰免密碼登入

Windows 版本的 OpenSSH Server 只能接受兩種認證方式 (AuthenticationMethods):

  1. Password-based authentication (password)
  2. Key-based authentication (publickey)

密碼驗證預設就是啟用的,而金鑰驗證則要特別設定 AuthorizedKeysFile 而且還要有正確的 NTFS 權限設定才能生效。詳見 Fix SSH file permissions 文章說明。

以下就是一個完整的設定過程步驟:

  1. 我們先在 Windows 主機建立一個帳號名稱為 user1 的使用者

    你可以使用 net user 命令快速建立使用者:

    net user user1 * /ADD
    

    過程中需要設定 user1 帳號的密碼,需輸入兩次。

  2. 嘗試從登入這台 Windows 的 OpenSSH Server

    我們可以用 ssh 命令直接登入 user1 使用者,預設會提示你要輸入密碼,這是 Windows OpenSSH 內建的 password 認證方法:

    ssh user1@localhost
    

    如果你想登入 AD 網域帳號,可以選擇以下任何一種語法:

    ssh -l user@domain host
    ssh domain\user@host
    ssh user@domain@host
    

    若要以 Kerberos Authentication 登入,可以參考這裡

    首次登入成功時 Windows 會自動建立 C:\Users\user1 這個所謂的 使用者設定檔 (User Profile) 資料夾,在還沒有任何登入紀錄前,是沒有這個目錄的。但在第一次登入成功後,預設就會啟動 OpenSSH Server 設定好的 DefaultShell (預設殼層),讓你可以進行遠端操作:

    image

  3. 建立 .ssh 資料夾

    只要是全新的使用者,我通常會在第一次遠端登入後立刻建立好一個 .ssh 資料夾:

    mkdir .ssh
    

    接著就可以輸入 exit 登出 Windows 遠端殼層環境。

    我們也可以在第一次 SSH 連線時就直接建立 .ssh 資料夾,底下命令可以一口氣建立好 User Profile 資料夾與相對應的 .ssh 資料夾

    ssh user1@localhost mkdir .ssh
    

    上述命令等於遠端登入 OpenSSH Server 並執行完 mkdir .ssh 之後自動登出。

  4. 建立 .ssh\authorized_keys 授權金鑰檔

    如果你想從一台 Windows 的 ssh 使用 publickey 無密碼遠端登入到另一台 Windows 的 OpenSSH Server,那麼你需要先學會如何透過 PowerShell 建立 SSH 金鑰組。命令很簡單,底下這一行就可以搞定:

    ssh-keygen -t rsa -b 4096 -f $HOME/.ssh/id_rsa -N '""'
    

    注意:Windows 上的 ssh-keygen-N 參數必須傳入 '""' 才能正確的產生出無密碼的私密金鑰,這很雷!

    # 複製你的公開金鑰到遠端的 .ssh/authorized_keys 檔案中 (此命令會覆蓋此檔案)
    scp $HOME/.ssh/id_rsa.pub 'user1@localhost:.ssh\authorized_keys'
    

    PowerShell 預設就有一個跟 Linux 完全一樣的 $HOME 環境變數喔!

    如果你想從一台 Linux 的 ssh 使用 publickey 無密碼遠端登入到另一台 Windows 的 OpenSSH Server,那麼你需要這樣建立 SSH 金鑰組:

    ssh-keygen -t rsa -b 4096 -f $HOME/.ssh/id_rsa -N ''
    
    # 複製你的公開金鑰到遠端的 .ssh/authorized_keys 檔案中 (此命令會覆蓋此檔案)
    scp $HOME/.ssh/id_rsa.pub 'user1@172.23.64.1:.ssh\authorized_keys'
    

    註1: 上述命令皆從 Linux 的 bash 環境下執行,路徑中有 \ 的話,命令列參數一定要用單引號 ' 框起來,否則路徑會有異常!

    註2: 若 Windows 主機上的 .ssh\authorized_keys 檔案有自己以外的一般使用者可讀取的話,該檔案就會自動失效,這是 OpenSSH Server 預設的安全機制,所以請注意該檔案的 NTFS 檔案權限設定。詳見 Fix SSH file permissions 文章說明。

    註3: 如果要在遠端殼層直接編輯文字檔,我會建議你安裝 Windows 版的 vim 來用!(choco install vim -y)

  5. 接著你就可以免密碼登入了,安全又可靠!

    ssh user1@localhost
    

    若是在 CI/CD 的環境下連線,我們可能會需要透過 -i 指定自訂的私密金鑰,此時你可以這樣執行:

    ssh -i .\id_rsa user@host
    ssh -i .\id_rsa -l user@domain host
    
    echo 'put -r shares/' | sftp -i .\id_rsa user@host:.
    

設定 sshd_configChrootDirectory 參數

我在設定 Windows 的 SFTP 支援時,通常會啟用 OpenSSH Server 的 ChrootDirectory 設定,將使用者透過 SFTP 登入時,限制在特定目錄下。這個設定在 Linux 設定 SFTP 的時候很常用,而 Windows 版的 OpenSSH Server 是從 v7.7.0.0 版 (2018/5/31)開始支援這個設定,如果你使用 Windows Server 2019 的 LTS 版本,記得要安裝最新版的 OpenSSH Server 才能正常使用。

通常我們會針對「特定使用者」不允許遠端登入,並且限制該使用者只能透過 SFTP 存取「特定資料夾」下的檔案,以增強檔案傳輸的安全性。

以下是設定步驟:

  1. 建立要讓 user1 使用者透過 SFTP 上傳/下載檔案的資料夾

    你可以在 Windows 主機上設定任意一個資料夾,只要該資料夾的權限可以讓 user1 可讀或可寫即可。

    mkdir C:\Files\user1
    

    如果你直接用 C:\Files\user1\Downloads 目錄的話,就不用特別建立,可以直接使用。

  2. 編輯 $env:ProgramData\ssh\sshd_config 檔案

    你只要從 Windows 開啟 $env:ProgramData\ssh\sshd_config 檔案,在該檔案最下方加入以下設定即可:

    Match User user1
      AllowTcpForwarding no
      ChrootDirectory C:\Files\user1
      ForceCommand internal-sftp
    

    這裡的 Match User user1 就是只針對單一使用者 user1 進行設定,最後的 ForceCommand internal-sftp 就是為了讓該 user1 使用者無法遠端登入主機,只能使用 SFTP 傳檔而已。這裡最重要的當然就是 ChrootDirectory 設定,他會把使用者「關在」特定一個目錄下,遠端透過 SFTP 操作檔案時,是完全看不到 Windows 電腦中的任何其他資料夾! 👍

  3. 重新啟動 sshd 服務

    Restart-Service sshd
    

測試 sftp 上傳檔案

  • 將目前資料夾所有檔案上傳到遠端預設目錄

    echo 'put -r *' | sftp user1@localhost:.
    

    這個命令會連同所有子目錄一併上傳到遠端電腦。

  • 將目前資料夾下的 shares/ 資料夾中所有檔案上傳到遠端預設目錄

    echo 'put -r shares/' | sftp user1@localhost:.
    

    注意: 上傳到遠端的目錄下,不會有個 shares 資料夾,而是只有來源端 shares/* 底下所有內容。

  • 批次上傳作業

    假設你有一堆已知檔名的檔案要上傳,你可以把所有 sftp 命令都先寫好,並且一次套用上傳。

    例如你的 batch_commands.txt 命令檔如下:

    cd UploadFiles
    put '046020882904913013298 20211028.pdf'
    put '051725312905913026483 20211029.pdf'
    

    接著你就可以用以下命令執行批次,sftp 會幫你依序執行所有命令:

    cat batch_commands.txt | sftp user1@localhost
    

相關連結

留言評論