DOC / 1458 SysAdminHub.ru

Как настроить безопасный SFTP-сервер на Windows с OpenSSH

Как настроить безопасный SFTP-сервер на Windows с OpenSSH

Шаг 1 — Подготовка и проверка окружения

Перед установкой SFTP-сервера проверим, не установлен ли OpenSSH ранее, свободен ли TCP-порт 22, а затем подготовим каталог и локальную группу для SFTP-пользователей.

Все команды выполняются в PowerShell от имени администратора.

Проверяем наличие службы OpenSSH

Get-Service sshd -ErrorAction SilentlyContinue | Format-List Name, Status, StartType

Если команда ничего не выводит, служба sshd в системе отсутствует.

Проверяем порт 22

Get-NetTCPConnection -State Listen -LocalPort 22 -ErrorAction SilentlyContinue

Если команда не возвращает результат, в данный момент TCP-порт 22 не прослушивается другим процессом.

Создаём каталог для SFTP

New-Item -ItemType Directory -Path 'D:\SFTP' -Force | Out-Null

В каталоге D:\SFTP будут размещаться персональные директории SFTP-пользователей.

Создаём локальную группу SFTP-пользователей

New-LocalGroup -Name 'sftpusers' -Description 'Пользователи SFTP сервера' -ErrorAction SilentlyContinue

После выполнения команды будет создана локальная группа sftpusers:

Name      Description
----      -----------
sftpusers Пользователи SFTP сервера

В дальнейшем именно к участникам этой группы мы применим ограничения OpenSSH.

Создание локальной группы sftpusers в Windows Server

Шаг 2 — Установка Win32-OpenSSH

Теперь установим OpenSSH-сервер. В нашем примере используется сборка Win32-OpenSSH из официального репозитория PowerShell на GitHub.

Скачиваем OpenSSH

Скачайте актуальный 64-битный архив OpenSSH-Win64.zip с GitHub.

Создаём временную папку

New-Item -ItemType Directory -Path 'C:\Temp' -Force | Out-Null

Скопируйте скачанный файл OpenSSH-Win64.zip в каталог C:\Temp.

Распаковываем OpenSSH

$zip  = 'C:\Temp\OpenSSH-Win64.zip'
$dest = 'C:\Program Files\OpenSSH'

New-Item -ItemType Directory -Path $dest -Force | Out-Null
Expand-Archive -Path $zip -DestinationPath $dest -Force

Проверяем структуру каталога

В зависимости от структуры архива файлы OpenSSH могут оказаться во вложенной директории. Проверить и при необходимости переместить их можно следующим блоком:

$nested = Get-ChildItem -Directory $dest | Where-Object {
    Test-Path "$($_.FullName)\sshd.exe"
}

if ($nested) {
    Move-Item -Path "$($nested.FullName)\*" -Destination $dest -Force
    Remove-Item $nested.FullName -Recurse -Force
}

Проверяем необходимые файлы

Get-ChildItem "$dest\sshd.exe","$dest\sftp-server.exe","$dest\Install-SSHD.ps1" -ErrorAction SilentlyContinue

В каталоге должны присутствовать как минимум:

sshd.exe
sftp-server.exe
Install-SSHD.ps1

Если файлы присутствуют, можно переходить к регистрации службы.

Шаг 3 — Регистрация и запуск службы OpenSSH

Устанавливаем службу sshd

Перейдите в каталог OpenSSH:

Set-Location 'C:\Program Files\OpenSSH'

Разблокируйте установочный скрипт и запустите его:

Unblock-File .\Install-SSHD.ps1
.\Install-SSHD.ps1

После установки проверьте наличие службы:

Get-Service sshd

Настроим автоматический запуск и запустим её:

Set-Service -Name sshd -StartupType Automatic
Start-Service sshd

Разрешаем подключения на TCP-порт 22

Создадим правило Windows Defender Firewall:

New-NetFirewallRule -Name 'OpenSSH-Server' `
    -DisplayName 'OpenSSH Server (TCP 22)' `
    -Direction Inbound `
    -Action Allow `
    -Protocol TCP `
    -LocalPort 22 `
    -Profile Any `
    -ErrorAction SilentlyContinue

Проверяем службу и порт

Get-Service sshd | Format-List Name, Status, StartType

Ожидаемый результат:

Name      : sshd
Status    : Running
StartType : Automatic

Теперь проверим TCP-порт:

Test-NetConnection -ComputerName localhost -Port 22

При успешном запуске получим:

TcpTestSucceeded : True

Шаг 4 — Настройка sshd_config в режиме SFTP-only

Теперь ограничим участников группы sftpusers только SFTP. Интерактивная SSH-сессия для них использоваться не будет.

В качестве начального каталога пользователя будет использоваться:

D:\SFTP\<имя_пользователя>

Настраиваем Subsystem sftp

Конфигурационный файл OpenSSH находится по адресу:

C:\ProgramData\ssh\sshd_config

Перед изменением конфигурации рекомендую сделать резервную копию:

Copy-Item 'C:\ProgramData\ssh\sshd_config' 'C:\ProgramData\ssh\sshd_config.bak' -Force

Затем выполним:

$cfg = 'C:\ProgramData\ssh\sshd_config'

New-Item -ItemType Directory -Path 'D:\SFTP' -Force | Out-Null

$raw = Get-Content $cfg -Raw
$raw = $raw -replace '(?m)^\s*Subsystem\s+sftp\s+.*$', 'Subsystem   sftp   "C:/Program Files/OpenSSH/sftp-server.exe"'
Set-Content -Path $cfg -Value $raw -Encoding ASCII

Добавляем Match Group sftpusers

В конец sshd_config необходимо добавить:

Match Group sftpusers
    ForceCommand "C:/Program Files/OpenSSH/sftp-server.exe" -d "D:/SFTP/%u"
    AllowTcpForwarding no
    X11Forwarding no
    PermitTTY no

Здесь:

  • Match Group sftpusers применяет настройки только к участникам группы;
  • ForceCommand запускает SFTP-сервер и задаёт начальный каталог пользователя;
  • AllowTcpForwarding no отключает TCP forwarding;
  • X11Forwarding no отключает X11 forwarding;
  • PermitTTY no запрещает выделение терминала.

Проверяем конфигурацию

Перед перезапуском службы обязательно проверьте синтаксис:

& 'C:\Program Files\OpenSSH\sshd.exe' -t -f $cfg

Если ошибок нет, команда ничего не выведет.

После успешной проверки перезапустите службу:

Restart-Service sshd

Шаг 5 — Создание пользователя и настройка NTFS-прав

Теперь создадим локального пользователя, добавим его в группу sftpusers и подготовим персональный каталог.

Создаём пользователя

$User = 'sftp-test1'
$Pwd  = Read-Host -AsSecureString 'Введите пароль для sftp-test1'

New-LocalUser `
    -Name $User `
    -Password $Pwd `
    -PasswordNeverExpires:$true `
    -AccountNeverExpires:$true `
    -Description 'Тестовый пользователь для SFTP'

Создание локального пользователя для SFTP

Добавляем пользователя в группу sftpusers

Add-LocalGroupMember -Group 'sftpusers' -Member $User

Добавление пользователя в локальную группу sftpusers

Настраиваем корневой каталог SFTP

icacls 'D:\SFTP' /inheritance:r
icacls 'D:\SFTP' /grant:r "Administrators:(OI)(CI)F"
icacls 'D:\SFTP' /grant "SYSTEM:(OI)(CI)F"

Корневой каталог D:\SFTP не должен предоставлять обычным SFTP-пользователям доступ к чужим домашним директориям.

Настраиваем домашний каталог пользователя

$UserHome  = "D:\SFTP\$User"
$LocalAcct = "$env:COMPUTERNAME\$User"

New-Item -ItemType Directory -Path $UserHome -Force | Out-Null

icacls $UserHome /inheritance:r
icacls $UserHome /grant:r "Administrators:(OI)(CI)F"
icacls $UserHome /grant "SYSTEM:(OI)(CI)F"
icacls $UserHome /grant "$($LocalAcct):(OI)(CI)M"

Проверить итоговые ACL можно командой:

icacls $UserHome

В результате администраторы и SYSTEM должны иметь полный доступ, а сам пользователь — права Modify только к своей директории.

Шаг 6 — Проверка подключения

Проверка через sftp.exe

Для первоначального теста можно использовать клиент из установленного комплекта OpenSSH:

& "C:\Program Files\OpenSSH\sftp.exe" sftp-test1@localhost

После ввода пароля появится приглашение:

Connected to localhost.
sftp>

Проверьте работу команд:

pwd
ls
mkdir test
ls
cd ..
ls
exit

Пользователь должен иметь возможность создавать и изменять данные внутри своей директории, но не должен получать доступ к каталогам, на которые у его учётной записи отсутствуют NTFS-права.

Проверка через WinSCP

Теперь проверим подключение через WinSCP:

  • протокол — SFTP;
  • хост — IP-адрес SFTP-сервера;
  • порт — 22;
  • имя пользователя — sftp-test1;
  • пароль — пароль, заданный при создании пользователя.

Подключение к SFTP-серверу Windows через WinSCP

Проверяем попытку выхода из домашнего каталога

Особое внимание уделите попытке перейти на уровень выше домашней директории.

В нашем тесте при первом переходе вверх WinSCP получил ошибку доступа:

Ошибка доступа при выходе из домашнего каталога SFTP

Однако дальнейшая проверка показала важную особенность используемой конфигурации.

Проверка перехода по файловой системе через SFTP

Клиент смог перейти выше и увидеть содержимое диска D:.

Просмотр корня диска D через SFTP

При дальнейшем переходе стало возможно увидеть доступные тома файловой системы.

Просмотр доступных дисков сервера через SFTP

Шаг 7 — Ограничение доступа к диску с SFTP

В нашем примере для SFTP выделен диск D:. Если этот том используется исключительно для SFTP, можно дополнительно ограничить доступ к его корню.

Сохраняем текущие ACL

Перед изменениями сохраните существующие права:

icacls D:\ /save C:\Temp\acl_backup_before_sftp_root.txt

Резервную копию лучше хранить не на томе, ACL которого вы собираетесь изменять.

Настраиваем права на выделенном SFTP-томе

Если D: действительно является отдельным томом исключительно для SFTP, после проверки существующих ACL можно применить ограниченную конфигурацию:

icacls D:\ /inheritance:r
icacls D:\ /remove "Users" "Authenticated Users" "Everyone"
icacls D:\ /grant:r "Administrators:(OI)(CI)F"
icacls D:\ /grant "SYSTEM:(OI)(CI)F"

После этого проверьте результат:

icacls D:\

Шаг 8 — Ограничение доступа к другим каталогам

Вместо массового изменения ACL системного диска C:\ безопаснее исходить из принципа минимальных прав: SFTP-пользователь не должен состоять в лишних локальных группах и не должен получать дополнительные разрешения на каталоги за пределами своей рабочей области.

Проверьте членство пользователя:

Get-LocalGroup | ForEach-Object {
    $Group = $_.Name

    Get-LocalGroupMember -Group $Group -ErrorAction SilentlyContinue |
        Where-Object { $_.Name -match 'sftp-test1' } |
        Select-Object @{Name='Group';Expression={$Group}}, Name
}

Также можно проверить конкретные каталоги, которые пользователь потенциально способен открыть:

icacls 'C:\'
icacls 'D:\'
icacls 'D:\SFTP'
icacls 'D:\SFTP\sftp-test1'

Шаг 9 — Автоматическое создание SFTP-пользователей

Когда базовая конфигурация проверена, создание пользователей можно автоматизировать. Скрипт будет:

  • создавать локального пользователя;
  • добавлять его в группу sftpusers;
  • создавать домашнюю директорию;
  • настраивать NTFS ACL;
  • создавать каталог upload;
  • добавлять файл README.txt.

Скрипт adduser.ps1

Готовый скрипт можно скачать здесь или создать файл C:\scripts\adduser.ps1.

Set-ExecutionPolicy -Scope Process Bypass -Force

$ErrorActionPreference = "Stop"
$Root = "D:\SFTP"

if (-not (Test-Path $Root)) {
    New-Item -ItemType Directory -Path $Root -Force | Out-Null
}

if (-not (Get-LocalGroup -Name 'sftpusers' -ErrorAction SilentlyContinue)) {
    New-LocalGroup -Name 'sftpusers' | Out-Null
}

$UserName = Read-Host "Введите ЛОГИН нового SFTP-пользователя"
$Desc     = Read-Host "Введите ОПИСАНИЕ пользователя"

function Read-Secret([string]$Prompt) {
    Read-Host -AsSecureString -Prompt $Prompt
}

do {
    $Pwd1 = Read-Secret "Введите ПАРОЛЬ"
    $Pwd2 = Read-Secret "Повторите ПАРОЛЬ"

    $b1 = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Pwd1)
    $p1 = [Runtime.InteropServices.Marshal]::PtrToStringUni($b1)
    [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($b1)

    $b2 = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Pwd2)
    $p2 = [Runtime.InteropServices.Marshal]::PtrToStringUni($b2)
    [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($b2)

    if ($p1 -ne $p2) {
        Write-Host "Пароли не совпадают, попробуйте снова." -ForegroundColor Yellow
    }
} until ($p1 -eq $p2)

if (-not (Get-LocalUser -Name $UserName -ErrorAction SilentlyContinue)) {
    New-LocalUser `
        -Name $UserName `
        -Password $Pwd1 `
        -PasswordNeverExpires:$true `
        -AccountNeverExpires:$true `
        -Description $Desc | Out-Null
}
else {
    $adsi = [ADSI]"WinNT://$env:COMPUTERNAME/$UserName,user"
    $adsi.SetPassword($p1)
    $adsi.SetInfo()

    Set-LocalUser -Name $UserName -Description $Desc
}

if (-not (
    Get-LocalGroupMember -Group 'sftpusers' -ErrorAction SilentlyContinue |
    Where-Object { $_.Name -ieq "$env:COMPUTERNAME\$UserName" }
)) {
    Add-LocalGroupMember -Group 'sftpusers' -Member $UserName
}

$UserHome = Join-Path $Root $UserName

New-Item -ItemType Directory -Path $UserHome -Force | Out-Null

icacls $Root /inheritance:r | Out-Null
icacls $Root /grant:r "Administrators:(OI)(CI)F" | Out-Null
icacls $Root /grant "SYSTEM:(OI)(CI)F" | Out-Null

$acct = "$env:COMPUTERNAME\$UserName"

icacls $UserHome /inheritance:r | Out-Null
icacls $UserHome /grant:r "Administrators:(OI)(CI)F" | Out-Null
icacls $UserHome /grant "SYSTEM:(OI)(CI)F" | Out-Null
icacls $UserHome /grant ("{0}:(OI)(CI)M" -f $acct) | Out-Null

$Upload = Join-Path $UserHome 'upload'

if (-not (Test-Path $Upload)) {
    New-Item -ItemType Directory -Path $Upload -Force | Out-Null
}

icacls $Upload /inheritance:r | Out-Null
icacls $Upload /grant:r "Administrators:(OI)(CI)F" | Out-Null
icacls $Upload /grant "SYSTEM:(OI)(CI)F" | Out-Null
icacls $Upload /grant ("{0}:(OI)(CI)M" -f $acct) | Out-Null

$readme = Join-Path $UserHome 'README.txt'

if (-not (Test-Path $readme)) {
    Set-Content $readme -Encoding UTF8 -Value "Добро пожаловать! Загружайте файлы в папку 'upload'."
}

Write-Host "Готово: $UserName → $UserHome. Описание: $Desc" -ForegroundColor Green

Запускаем скрипт

cd C:\scripts
.\adduser.ps1

После выполнения скрипта новый пользователь появится в группе sftpusers, а в D:\SFTP будет создан его персональный каталог.

Проверяем нового пользователя

Подключитесь через WinSCP:

  • протокол — SFTP;
  • хост — IP-адрес сервера;
  • порт — 22;
  • имя пользователя — созданная учётная запись;
  • пароль — пароль, указанный при запуске скрипта.

После входа пользователь должен иметь доступ к своей директории и папке upload.

Проверка нового SFTP-пользователя через WinSCP

FAQ

Можно ли развернуть SFTP-сервер на Windows Server?

Да. Для этого можно использовать OpenSSH Server. Пользователи подключаются по протоколу SFTP через TCP-порт 22, а управление сервером и конфигурацией выполняется стандартными средствами Windows и PowerShell.

Чем SFTP отличается от FTP?

SFTP работает поверх SSH и использует защищённое соединение. Обычный FTP без дополнительного шифрования передаёт данные и учётные сведения небезопасным способом.

Можно ли разрешить SFTP, но запретить пользователю обычный SSH?

Да. В OpenSSH для участников отдельной группы можно использовать блок Match Group и параметр ForceCommand, принудительно запускающий SFTP-сервер вместо обычной интерактивной SSH-сессии.

ForceCommand изолирует пользователя внутри его домашней папки?

Нет. Параметр -d задаёт начальный каталог SFTP-сеанса, но не превращает его в настоящий chroot. Доступ пользователя к другим каталогам Windows определяется в том числе NTFS-разрешениями.

Как запретить SFTP-пользователю просматривать чужие файлы?

Необходимо правильно настроить NTFS ACL: пользователь должен иметь необходимые права на свою рабочую директорию и не получать разрешений на чужие каталоги. После настройки обязательно проверьте фактический доступ под тестовой учётной записью.

Нужно ли открывать порт 22 в Windows Firewall?

Да, если к SFTP-серверу будут подключаться с других компьютеров. При этом лучше ограничить правило нужными сетями или IP-адресами, если архитектура инфраструктуры это позволяет.

Можно ли использовать доменные учётные записи Active Directory?

Да, OpenSSH в Windows может работать с доменными учётными записями, однако настройка групп, идентификаторов пользователей и NTFS-разрешений будет отличаться от рассмотренного здесь сценария с локальными пользователями.

Заключение

Мы настроили SFTP-сервер на Windows с помощью OpenSSH: установили и запустили службу sshd, ограничили отдельную группу пользователей режимом SFTP-only, создали персональные каталоги и настроили NTFS-права.

Главный момент такой конфигурации — не путать начальную директорию SFTP с полноценным chroot. В Windows OpenSSH фактический доступ пользователя к файловой системе необходимо контролировать с помощью NTFS ACL и обязательно проверять под обычной пользовательской учётной записью.

После проверки базовой конфигурации создание новых SFTP-пользователей можно автоматизировать PowerShell-скриптом. Это значительно упрощает дальнейшее администрирование сервера и позволяет выдавать отдельные каталоги сотрудникам или внешним контрагентам без ручной настройки каждого пользователя.

Вам понравилась эта статья? Тогда вам, скорее всего, будет интересна другая полезная статья Проверка состояния Active Directory с помощью PowerShell.

ORIGINAL / ATTRIBUTION

Источник материала

Материал взят с https://sysadminhub.ru/. Оригинальная статья и авторство указаны по ссылке ниже.

Оригинал статьи на SysAdminHub.ru ↗

https://sysadminhub.ru/produkty-microsoft/windows-server/configuring-the-sftp-server-on-windows-openssh

Материал проверен 10.10.2026. При изменении программного обеспечения сверяйтесь с актуальной документацией.
← Вернуться в базу знаний