Защита RDP от брутфорса: как автоматически блокировать IP атакующих

5 мин чтения · обновлено 27 сентября 2026

Сервер с RDP на стандартном порту 3389 начинают перебирать через несколько минут после появления в интернете. Защита RDP от брутфорса складывается из двух частей: базовых настроек, которые уменьшают риск, и автоматической блокировки IP, с которых подбирают пароль. Ниже обе части по шагам, с готовым скриптом PowerShell и честным разбором его ограничений.

Базовые меры защиты RDP

  • Не открывайте RDP в интернет, если можно. Лучший вариант: доступ через VPN или шлюз удалённых рабочих столов (RD Gateway). Тогда порт 3389 снаружи просто закрыт.
  • Ограничьте доступ по IP. Если подключаются только из офиса, разрешите в правиле брандмауэра Windows для RDP только адреса офиса.
  • Включите NLA (проверку подлинности на уровне сети). Без неё сервер показывает окно входа любому, кто подключился.
  • Уберите простые пароли и переименуйте Administrator. Боты перебирают в первую очередь administrator, admin, user и похожие имена.
  • Осторожно с политикой блокировки учётных записей. Она останавливает перебор, но блокирует и настоящего пользователя: атакующий, перебирая пароль, фактически отключает сотруднику доступ.
  • Смена порта уменьшает шум от массовых сканеров, но не защищает: нестандартный порт находится обычным сканированием.

Если RDP всё же открыт в интернет, нужна автоматическая блокировка атакующих IP.

Где Windows записывает неудачные входы по RDP

Основной источник: журнал безопасности, событие 4625 («Не удалось выполнить вход в учётную запись»). В нём есть поле «Сетевой адрес источника» с IP атакующего и тип входа: 10 для RDP без NLA и 3 для входа с NLA.

У события 4625 есть две особенности:

  • Оно не только про RDP. Тем же событием записываются неудачные входы по SMB и другим сетевым протоколам. Для защиты это скорее плюс: перебор через SMB тоже стоит блокировать.
  • При NLA IP часто пустой. Вместо адреса стоит прочерк. Тогда IP нужно брать из журнала Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational, событие 140: в его тексте указан IP клиента, который ввёл неверное имя пользователя или пароль.

Событие 4625 пишется, только если включён аудит неудачных входов. Проверить можно так (GUID работает и в русской, и в английской Windows):

auditpol /get /subcategory:"{0CCE9215-69AE-11D9-BED3-505054503030}"

В ответе у подкатегории входа в систему должен стоять «Сбой» (Failure). Если нет, включите:

auditpol /set /subcategory:"{0CCE9215-69AE-11D9-BED3-505054503030}" /failure:enable

Скрипт PowerShell: автоматическая блокировка IP при переборе RDP

Скрипт ниже собирает IP из событий 4625 и 140 за последние 2 часа, находит адреса с 5 и больше неудачными попытками и добавляет их в блокирующее правило брандмауэра Windows. Сохраните его как C:\Scripts\block-rdp-bruteforce.ps1:

# Блокирует IP, с которых за последние 2 часа было 5 и больше неудачных входов
$Threshold = 5
$Since     = (Get-Date).AddHours(-2)
$RuleName  = 'Block RDP brute-force'
$Allow     = @('203.0.113.10')   # внешние адреса офиса и VPN, которые нельзя блокировать
$IpRegex   = '\b(\d{1,3}(?:\.\d{1,3}){3})\b'

# 1. Журнал безопасности, событие 4625: поле IpAddress (Properties[19])
$ips = @(Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=$Since} -ErrorAction SilentlyContinue |
  ForEach-Object { $_.Properties[19].Value })

# 2. Журнал RdpCoreTS, событие 140: IP в тексте события (нужен при NLA, когда в 4625 прочерк)
$ips += Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational'; Id=140; StartTime=$Since} -ErrorAction SilentlyContinue |
  ForEach-Object { if ($_.Message -match $IpRegex) { $Matches[1] } }

$bad = $ips |
  Where-Object { $_ -match "^$IpRegex$" -and $_ -notin $Allow -and $_ -ne '127.0.0.1' } |
  Group-Object | Where-Object Count -ge $Threshold |
  Select-Object -ExpandProperty Name
if (-not $bad) { return }

$rule = Get-NetFirewallRule -DisplayName $RuleName -ErrorAction SilentlyContinue
if ($rule) {
  $old = @(($rule | Get-NetFirewallAddressFilter).RemoteAddress)
  $all = @($old + $bad | Sort-Object -Unique)
  Set-NetFirewallRule -DisplayName $RuleName -RemoteAddress $all
} else {
  New-NetFirewallRule -DisplayName $RuleName -Direction Inbound -Action Block `
    -Protocol TCP -LocalPort 3389 -RemoteAddress $bad | Out-Null
}

Если событие 4625 и событие 140 пишутся на одну и ту же попытку, она посчитается дважды. С порогом 5 это значит, что бан наступит примерно после третьей попытки. Для защиты RDP это нормально.

Запуск по расписанию

Запускайте скрипт каждые 5 минут от имени SYSTEM:

schtasks /create /tn "Block RDP brute-force" /sc minute /mo 5 /ru SYSTEM /rl HIGHEST /tr "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\block-rdp-bruteforce.ps1"

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

(Get-NetFirewallRule -DisplayName 'Block RDP brute-force' | Get-NetFirewallAddressFilter).RemoteAddress

Ограничения самописной защиты RDP

Скрипт закрывает базовую задачу, но у него есть предсказуемые слабые места:

  • Баны вечные. Адрес никогда не удаляется из правила. Список растёт, а случайно заблокированный клиент остаётся заблокированным, пока вы не уберёте его вручную.
  • Закрыт только RDP. Тот же IP продолжает перебирать MS SQL, почту или SMB, если они открыты.
  • Каждый сервер сам по себе. Бот, забаненный на одном сервере, начинает всё сначала на следующем. На десятке серверов скрипт, whitelist и порог нужно поддерживать в десяти местах.
  • Никто не узнает. Нет ни уведомлений, ни общей картины, кого и где заблокировали.

Защита RDP от брутфорса на всех серверах сразу

KIPBan делает то же самое, но без этих ограничений. Агент на Windows:

  • читает события 4625 и журнал RdpCoreTS, а также журналы других служб: RD Web, MS SQL, MySQL, почтовых серверов, VNC, VPN/RRAS, OpenSSH для Windows;
  • по умолчанию банит IP после 3 неудачных попыток подряд, если между ними прошло не больше 5 минут, и блокирует адрес на всех портах;
  • снимает бан по сроку: 3 дня за первое нарушение, 30 дней за второе, дальше навсегда;
  • не трогает адреса локальной сети и адреса из whitelist, в том числе подсети CIDR;
  • сразу отправляет IP в общий бан-лист, и остальные ваши серверы, Windows и Linux, блокируют его в течение 5 минут;
  • присылает уведомление в Telegram с именем сервера, IP и логином, под которым пытались войти.

Подробнее о том, как это устроено и чем отличается от других программ, в статье «Fail2ban для Windows». Все поля события 4625 и коды причин отказа описаны в документации Microsoft.

Вопросы про защиту RDP

Какой Event ID у неудачного входа по RDP?

В журнале безопасности это событие 4625, IP атакующего записан в поле «Сетевой адрес источника». Если включён NLA и в 4625 вместо адреса прочерк, IP есть в журнале RemoteDesktopServices-RdpCoreTS/Operational, событие 140.

Поможет ли смена порта RDP?

Частично. Смена порта отсекает часть массовых сканеров, но нестандартный порт находится обычным сканированием. Это дополнение к блокировке IP, а не замена.

Почему не включить блокировку учётных записей?

Её можно включить, но она блокирует пользователя, а не атакующего. Бот, перебирающий пароль к учётной записи сотрудника, фактически лишает его доступа. Блокировка по IP останавливает сам источник атаки.

Как разблокировать IP, заблокированный скриптом?

Уберите адрес из правила: получите текущий список через Get-NetFirewallAddressFilter, удалите из него адрес и запишите обратно командой Set-NetFirewallRule с параметром RemoteAddress. Чтобы адрес больше не блокировался, добавьте его в массив $Allow.