Выберите продукт

nftables connlimit и rate limit против brute force: лимиты SSH и связка с Fail2ban

Практический рецепт, как быстро приглушить bruteforce по SSH на Linux с помощью nftables: ограничим частоту новых подключений (rate limit) и число параллельных сессий (connlimit-логика). Плюс аккуратная интеграция с Fail2ban через nft set и подсказки по отладке.
nftables connlimit и rate limit против brute force: лимиты SSH и связка с Fail2ban

Bruteforce по SSH и другим публичным сервисам редко «ломает» пароль мгновенно, но почти всегда создаёт нагрузку: забивает логи, держит демоны в busy, нагружает сеть и подсистему аутентификации. На практике важнее быстро и предсказуемо срезать поток попыток, чем пытаться угадать все IP-адреса атакующих.

На Linux для этого удобно комбинировать два слоя:

  • nftables — режет шум на входе: ограничивает скорость новых подключений (rate limit) и/или число параллельных соединений (connlimit-логика).
  • Fail2ban — по логам выделяет «упорных» нарушителей и банит их на минуты/часы.

Ниже — практическая схема: сначала базовые лимиты в nftables, затем привязка Fail2ban к nft set без зоопарка из разных фаерволов.

Что именно ограничивать: параллельные соединения и скорость новых попыток

У bruteforce по SSH обычно два профиля, и под каждый нужен свой тормоз:

  • Шторм коротких подключений (частые new-сессии): важно ограничить скорость новых соединений на порт 22, то есть ct state new.
  • Накопление параллельных сессий (держат много соединений «висящими»): важно ограничить количество одновременных соединений на источник (connlimit-логика).

Эти лимиты не взаимозаменяемы: можно иметь низкую скорость новых соединений, но много параллельных (если соединения держат долго), и наоборот.

Где применять лимиты: на входе или на уровне демона

Оптимально ограничивать на цепочке input в таблице inet — до того, как соединение доберётся до SSH и начнёт потреблять ресурсы приложения. При этом почти всегда лимитируют именно ct state new, чтобы не ломать уже установленные интерактивные сессии.

Практический принцип: rate limit режет «всплески», connlimit защищает от «залипания». Вместе они дают предсказуемое поведение под атакой.

Базовый каркас nftables для SSH: минимально безопасно и расширяемо

Ниже — каркас, куда удобно встраивать SSH-защиту. Семейство inet позволяет одним ruleset покрыть IPv4 и IPv6. Политика по умолчанию — drop, так что убедитесь, что добавили все нужные разрешения (SSH, мониторинг, сервисы).

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
  chain input {
    type filter hook input priority 0;
    policy drop;

    ct state established,related accept
    iifname "lo" accept

    ip protocol icmp accept
    ip6 nexthdr icmpv6 accept

    tcp dport 22 ct state new jump ssh_guard
    tcp dport 22 accept

    reject with icmpx type admin-prohibited
  }

  chain ssh_guard {
    return
  }
}

Почему отдельная цепочка ssh_guard: туда удобно складывать rate limit, проверки по динамическим наборам (sets) от Fail2ban, счётчики и аккуратное логирование.

Если вы держите проекты на VDS, такой каркас помогает быстро включить базовую защиту до установки/настройки прикладных средств — и затем спокойно её расширять.

Пример правил nftables для ограничения новых SSH-подключений

Ограничиваем скорость новых SSH-подключений (rate limit по источнику)

Самая надёжная и переносимая часть: ограничивать частоту новых соединений на порт 22. В nftables это делается через выражение limit в сочетании с ct state new. По смыслу это «hashlimit-подобная» логика: вы ограничиваете поток событий, не трогая уже установленные соединения.

Пример: разрешить до 5 новых соединений в минуту (с небольшим burst), всё сверх — отбрасывать. Значения подбирайте под реальность (офисный NAT, VPN, bastion, автоматизация).

table inet filter {
  chain ssh_guard {
    ct state new limit rate 5/minute burst 10 packets counter return

    counter
    log prefix "SSH rate limit: " flags all level warning
    drop
  }
}

Почему return: мы возвращаемся в input, где дальше сработает tcp dport 22 accept. Цепочка ssh_guard отвечает только за «лишнее».

Как подобрать значения, чтобы не заблокировать себя

  • Только вы с одного IP: обычно хватает 3–5 новых соединений в минуту, burst 6–12.
  • Офис/провайдерский NAT: увеличивайте лимит или делайте allowlist для офисного IP/подсети до лимитов.
  • CI/CD, Ansible, мониторинг: частые короткие SSH-сессии легко утыкаются в лимит. Для таких источников — отдельные правила (allowlist) или доступ через bastion.

Если сомневаетесь — начните только с rate limit на ct state new. Он даёт максимальный эффект против bruteforce при минимальном риске само-блокировки.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Connlimit-логика: ограничиваем параллельные SSH-сессии

Идея: один реальный пользователь редко держит десятки одновременных SSH-сессий с одного IP, а атака может держать много «висящих» соединений, съедая дескрипторы, память и обработчики.

Нюанс: в iptables был привычный модуль connlimit, а в nftables «как в одну строку для всех» может отличаться по синтаксису и возможностям в зависимости от версии ядра и nft. Поэтому безопасный подход такой:

  • rate limit по ct state new — основная линия защиты (стабильно и почти везде одинаково работает);
  • ограничение параллельных соединений — как дополнительный слой, который вы внедряете после теста на своей платформе.

Практическая заготовка (как «место под connlimit»): добавьте отдельное правило в ssh_guard до rate limit и проверьте поддержку конкретного выражения в вашей версии nft. Если выражение не поддерживается, оставьте только rate limit и компенсируйте на стороне sshd параметрами вроде MaxStartups и таймаутами.

table inet filter {
  chain ssh_guard {
    # Connlimit-логика (пример-ориентир): если уже слишком много активных SSH-соединений от источника,
    # то новые попытки режем.
    # Синтаксис зависит от версии nft/ядра, поэтому внедряйте только после проверки.

    # пример-ориентир (псевдокод): ct count over 6 drop

    return
  }
}

Если хочется углубиться именно в динамические механики (sets, таймауты, массовые блок-листы), полезно посмотреть материал про динамические наборы в nftables и автоматические блокировки.

Fail2ban + nftables: кто за что отвечает

Роли лучше разделить так:

  • nftables — мгновенно и дёшево режет поток (rate limit/connlimit-логика) и отбрасывает явно лишнее.
  • Fail2ban — по логам SSH определяет повторяющиеся неуспешные логины и банит источник на время.

Лучший способ «подружить» их — чтобы Fail2ban писал IP-адреса в nftables set, а nftables проверял этот set самым первым правилом для SSH. Тогда правила остаются компактными, а баны применяются мгновенно.

Создаём nft set под баны и проверяем его в начале ssh_guard

Пример для IPv4. Если у вас есть IPv6-доступ на SSH — заведите второй набор для ipv6_addr и проверяйте ip6 saddr отдельно.

table inet filter {
  set f2b_ssh4 {
    type ipv4_addr
    flags timeout
  }

  chain ssh_guard {
    ip saddr @f2b_ssh4 counter drop

    ct state new limit rate 5/minute burst 10 packets counter return

    counter drop
  }
}

Почему set лучше, чем «отдельное правило на каждый IP»:

  • меньше правил и быстрее обработка при большом числе банов;
  • удобные таймауты на уровне nftables;
  • проще сопровождать и отлаживать.

Какие команды должен выполнять action Fail2ban (концептуально)

Fail2ban action обычно делает добавление/удаление элемента в set. Важно, чтобы таблица и set существовали до старта Fail2ban, иначе бан «не прилипнет».

nft add element inet filter f2b_ssh4 { 203.0.113.10 timeout 1h }
nft delete element inet filter f2b_ssh4 { 203.0.113.10 }

Если вы одновременно настраиваете и периметр, и защиту админки, держите единый подход (один фаервол-стек). Отдельно может пригодиться разбор общей практики защиты SSH на сервере: как аккуратно закрывать SSH фаерволом без потери доступа.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Отладка: как понять, что ограничения реально работают

Смотрим правила и счётчики

Счётчики (counter) — лучший компромисс: видно, что срабатывает, но нет лог-DoS при атаке.

nft list ruleset
nft list chain inet filter ssh_guard
nft list set inet filter f2b_ssh4

Проверяем симптомы «залипания» соединений

Если атака держит много установленных соединений, смотрите реальную картину по сокетам и общему числу established:

ss -tan sport = :22 | head
ss -tan state established '( sport = :22 )' | wc -l

Если вы утыкаетесь в лимиты conntrack на уровне системы, одного SSH-лимита может быть мало: нужно разбирать общую сетевую нагрузку и параметры conntrack — это уже отдельная задача.

Логи SSH и срабатывания ограничений и банов

Типовые ошибки и как их избежать

Ошибка 1: лимитируете весь трафик на порт 22 вместо ct state new

Если ограничивать не новые подключения, а все пакеты, можно «подрезать» уже установленные SSH-сессии. Для SSH почти всегда лимитируют именно новые соединения: ct state new.

Ошибка 2: слишком жёсткий лимит без burst

Плохая сеть, автопереподключения клиента, multiplexing, параллельные задачи — всё это может кратковременно дать всплеск. Добавляйте burst и сначала тестируйте в двух сессиях, имея доступ к консоли провайдера.

Ошибка 3: агрессивное логирование на каждый drop

При атаке логирование само становится DoS. Лучше опираться на counter, а если нужен лог — логируйте реже отдельным правилом с дополнительным limit.

Ошибка 4: Fail2ban банит не туда

Частая история: nftables фильтрует трафик, а Fail2ban продолжает банить через iptables, или наоборот. Приведите всё к одной модели и явно проверьте, что баны попадают именно в ваш nft set.

Практический рецепт «за 10 минут»

  1. Вынесите SSH в отдельную цепочку ssh_guard.

  2. Добавьте rate limit на ct state new с разумным burst и counter.

  3. Создайте nft set под баны Fail2ban и проверяйте его первым правилом в ssh_guard.

  4. Настройте Fail2ban action на nft add element и nft delete element для этого набора.

  5. Проверьте счётчики и убедитесь, что при тестах растёт число срабатываний на лимитах.

Итоги

Связка nftables + Fail2ban хорошо работает, если разделить обязанности: nftables мгновенно «гасит шум» (rate limit новых соединений и при необходимости connlimit-логика), а Fail2ban точечно банит тех, кто систематически ломится по логам аутентификации.

Делайте отдельную цепочку под SSH, лимитируйте именно ct state new, используйте burst, полагайтесь на counter вместо лог-спама — и получите устойчивую защиту, которая не мешает администрированию даже под заметной атакой.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...