Rate limiting для Minecraft: ограничение вредоносных подключений

Rate limiting для Minecraft: ограничение вредоносных подключений

Бот-атака на Minecraft сервер выглядит просто: сотни подключений в секунду с разных IP-адресов. Каждый бот устанавливает TCP-соединение, отправляет handshake, иногда даже проходит login. Сервер тратит ресурсы на каждое соединение, и в какой-то момент перестает отвечать настоящим игрокам.

Rate limiting решает эту проблему в лоб: если с одного IP приходит больше N подключений в секунду, лишние отбрасываются. Просто, грубо, эффективно. Но дьявол в деталях. Неправильно настроенный rate limiter заблокирует легитимных игроков, а слишком мягкий не остановит атаку.

В этой статье разберем все уровни rate limiting для Minecraft: от iptables до плагинов. С конкретными конфигами и объяснениями, почему именно такие значения.

Что такое rate limiting

Rate limiting - это механизм ограничения частоты запросов. Вместо того чтобы решать, хороший запрос или плохой (это задача файрвола или антибота), rate limiter просто считает: сколько запросов пришло от этого источника за единицу времени. Превысил порог - получи отказ.

Это работает, потому что нормальный игрок подключается к серверу один раз. Может два, если вылетел и перезашел. Десять раз в минуту - уже подозрительно. Сто раз в секунду - точно бот.

Rate limiting применяется на разных уровнях:

  • Сетевой уровень (L3/L4) - iptables, nftables. Считает TCP-соединения и пакеты. Самый быстрый, работает в ядре.
  • Прокси-уровень (L7) - Velocity, BungeeCord, Waterfall. Считает Minecraft-подключения. Понимает протокол, может различать handshake и login.
  • Уровень приложения - плагины на самом сервере. Самый гибкий, но и самый ресурсоемкий.

Лучшая защита - комбинация всех трёх уровней. Каждый отсекает свой тип атаки.

server.properties: встроенный rate-limit

В server.properties есть параметр rate-limit, о котором мало кто знает:

# server.properties
rate-limit=0

По умолчанию он равен 0 (отключен). Если установить значение, сервер будет отключать клиентов, которые отправляют больше указанного количества пакетов в секунду.

# Разумное значение для большинства серверов
rate-limit=500

500 пакетов в секунду - это много для обычного игрока. Нормальная игра генерирует 20-50 пакетов в секунду (движение, взаимодействие, чат). Даже активный PvP редко превышает 200. Но боты, использующие packet spam, легко генерируют тысячи.

Ограничения

Этот параметр работает уже после установки соединения. Бот, который просто спамит подключениями без отправки пакетов, его не заденет. Для защиты от connection flood нужны другие инструменты.

Кроме того, на Paper этот параметр фактически заменен встроенным packet limiter:

# paper-global.yml
packet-limiter:
  kick-message: '<red><lang:disconnect.exceeded_packet_rate>'
  limits:
    all:
      interval: 7.0
      max-packet-rate: 500.0
    ServerboundCommandSuggestionPacket:
      interval: 1.0
      max-packet-rate: 15.0

Paper-реализация гибче: можно задать лимиты для конкретных типов пакетов. Tab-complete спам? Ограничьте ServerboundCommandSuggestionPacket до 15 в секунду. Подозрительно много пакетов движения? ServerboundMovePlayerPacket до 50 в секунду.

iptables: rate limiting на уровне ядра

iptables - самый мощный инструмент для rate limiting на Linux. Работает в ядре, не тратит ресурсы userspace, обрабатывает пакеты до того, как они дойдут до Java-процесса.

Если вы не знакомы с основами iptables, прочитайте наш гайд по настройке iptables для Minecraft.

connlimit: ограничение одновременных соединений

Модуль connlimit ограничивает количество одновременных TCP-соединений с одного IP-адреса.

# Максимум 3 одновременных соединения на порт 25565 с одного IP
iptables -A INPUT -p tcp --dport 25565 \
  -m connlimit --connlimit-above 3 \
  -j DROP

Почему 3? Потому что игрок обычно имеет одно активное соединение. Два - если переподключается (старое еще не закрылось). Три - запас на всякий случай. Бот-атака с одного IP создает десятки и сотни соединений, и connlimit отсечет все, что выше порога.

Для BungeeCord/Velocity сети, где прокси подключается к backend-серверам, нужно вайтлистить IP прокси:

# Разрешить прокси без ограничений
iptables -A INPUT -p tcp --dport 25565 -s 10.0.0.1 -j ACCEPT

# Ограничить остальных
iptables -A INPUT -p tcp --dport 25565 \
  -m connlimit --connlimit-above 3 \
  -j DROP

hashlimit: ограничение скорости подключений

connlimit ограничивает одновременные соединения, но не скорость создания новых. Бот может создавать и закрывать соединения быстрее, чем connlimit их считает. Для этого нужен hashlimit.

# Максимум 10 новых соединений в секунду с одного IP
iptables -A INPUT -p tcp --dport 25565 --syn \
  -m hashlimit \
  --hashlimit-name minecraft \
  --hashlimit-above 10/sec \
  --hashlimit-burst 20 \
  --hashlimit-mode srcip \
  --hashlimit-htable-expire 30000 \
  -j DROP

Разберем параметры:

  • --syn - считаем только SYN-пакеты (начало нового соединения)
  • --hashlimit-above 10/sec - порог: больше 10 соединений в секунду
  • --hashlimit-burst 20 - разрешить всплеск до 20 (для легитимного reconnect)
  • --hashlimit-mode srcip - считать отдельно для каждого IP
  • --hashlimit-htable-expire 30000 - очищать записи через 30 секунд неактивности

10 соединений в секунду - это щедрый лимит для одного игрока. Даже при плохом соединении, когда клиент постоянно переподключается, он не достигнет этого порога. Но бот, генерирующий сотни соединений, будет остановлен.

recent: простой rate limiter

Модуль recent - более простая альтернатива hashlimit. Он запоминает IP-адреса и считает попадания.

# Создаем цепочку для rate limiting
iptables -N MC_RATELIMIT

# Помечаем каждое новое соединение
iptables -A MC_RATELIMIT -m recent --name mc_conn --set

# Если больше 15 за 60 секунд - блокируем
iptables -A MC_RATELIMIT -m recent --name mc_conn \
  --rcheck --seconds 60 --hitcount 15 \
  -j DROP

# Иначе пропускаем
iptables -A MC_RATELIMIT -j ACCEPT

# Направляем новые подключения в нашу цепочку
iptables -A INPUT -p tcp --dport 25565 --syn \
  -j MC_RATELIMIT

recent проще настроить, но он менее точен, чем hashlimit. Для небольших серверов с трафиком до 100 игроков этого достаточно.

Комбинация правил

На практике используют несколько правил вместе:

# 1. Разрешить localhost и доверенные IP
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 25565 -s 10.0.0.1 -j ACCEPT

# 2. Разрешить установленные соединения
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 3. Ограничить одновременные соединения
iptables -A INPUT -p tcp --dport 25565 \
  -m connlimit --connlimit-above 3 -j DROP

# 4. Ограничить скорость новых соединений
iptables -A INPUT -p tcp --dport 25565 --syn \
  -m hashlimit \
  --hashlimit-name minecraft \
  --hashlimit-above 10/sec \
  --hashlimit-burst 20 \
  --hashlimit-mode srcip \
  -j DROP

# 5. Принять оставшиеся
iptables -A INPUT -p tcp --dport 25565 -j ACCEPT

Порядок важен. Сначала пропускаем доверенных, потом фильтруем по количеству, потом по скорости. Каждое правило отсекает свой слой мусора.

Velocity: connection throttle

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

# velocity.toml
[advanced]
connection-timeout = 5000
login-ratelimit = 3000

login-ratelimit - минимальное время (в миллисекундах) между попытками подключения с одного IP. Значение 3000 означает: максимум одно подключение каждые 3 секунды с одного IP.

Для серверов с большим количеством игроков за NAT (школы, интернет-кафе) значение можно поднять до 1000 (одно подключение в секунду). Для маленьких серверов 3000-5000 - хороший баланс.

BungeeCord connection_throttle

BungeeCord имеет аналогичную настройку:

# config.yml (BungeeCord)
connection_throttle: 4000
connection_throttle_limit: 3

connection_throttle: 4000 - минимальный интервал между подключениями (4 секунды). connection_throttle_limit: 3 - после трех нарушений IP блокируется.

Waterfall

Waterfall (форк BungeeCord от PaperMC) использует те же настройки, но добавляет дополнительные:

# waterfall.yml
connection_throttle: 4000
throttle: 4000

Рекомендация: если вы на BungeeCord, переходите на Velocity. Он быстрее, безопаснее, и лучше обрабатывает rate limiting. Подробнее о сравнении в нашей статье Velocity vs BungeeCord.

Token bucket: алгоритм, который стоит за всем этим

Большинство rate limiter-ов используют алгоритм token bucket (корзина с жетонами). Идея простая:

  1. У каждого IP есть "корзина" с жетонами
  2. Каждый запрос забирает один жетон
  3. Жетоны добавляются в корзину с фиксированной скоростью (например, 10 в секунду)
  4. Корзина имеет максимальную емкость (например, 50 жетонов)
  5. Если жетонов нет, запрос отклоняется

Почему это лучше простого счетчика "N запросов в секунду"? Потому что token bucket обрабатывает всплески. Если игрок не подключался 5 секунд, его корзина полная (50 жетонов). Он может быстро переподключиться 10 раз подряд, и все подключения пройдут. А бот, который постоянно генерирует трафик, быстро опустошит свою корзину.

Пример на псевдокоде:

bucket_size = 50        # максимум жетонов
refill_rate = 10        # жетонов в секунду
tokens = bucket_size    # начинаем с полной корзины

function handle_request(ip):
    bucket = get_bucket(ip)
    bucket.refill()     # добавить жетоны за прошедшее время

    if bucket.tokens > 0:
        bucket.tokens -= 1
        return ACCEPT
    else:
        return DROP

hashlimit в iptables работает по похожему принципу. --hashlimit-burst - это размер корзины, --hashlimit-above - скорость пополнения (инвертированная: это порог, выше которого начинается блокировка).

Плагины для rate limiting

LimboFilter

LimboFilter - это плагин для Velocity, который создает "предбанник" перед основным сервером. Новые подключения попадают на легковесный limbo-сервер, где проходят проверку (captcha, falling check), и только после этого перенаправляются на основной сервер.

Rate limiting здесь работает на уровне Minecraft-протокола. LimboFilter считает подключения, отслеживает повторные попытки, и может блокировать IP, который слишком часто пытается подключиться.

Подробнее о captcha-защите в нашей статье о капче для Minecraft.

BotSentry

BotSentry - плагин для BungeeCord/Velocity, специализирующийся на защите от ботов. Включает rate limiting как одну из функций:

  • Ограничение подключений в секунду (глобально и per-IP)
  • Автоматическая блокировка IP при превышении порога
  • Интеграция с внешними blocklist-ами
  • Настраиваемые действия (kick, tempban, captcha)

EPL (ExtraProxyLimiter)

Легковесная альтернатива для Velocity:

  • Считает подключения per-IP и глобально
  • Настраиваемые пороги для разных действий
  • Минимальное влияние на производительность

Тонкая настройка: как не заблокировать своих

Rate limiting - это баланс. Слишком строгие лимиты блокируют легитимных игроков. Слишком мягкие бесполезны. Вот несколько ситуаций, где нужна особая настройка.

Открытие сервера

Когда вы объявляете открытие нового сервера и приходит 500 игроков одновременно, стандартный rate limiter может заблокировать половину из них. Решения:

  1. Временно повысить лимиты. Перед открытием увеличьте hashlimit-burst и hashlimit-above. После стабилизации верните обратно.
  2. Использовать очередь. Velocity Limbo или LimboFilter может создать очередь, пропуская игроков порциями.
  3. Градуальный запуск. Сначала пустите по инвайтам, потом откройте для всех.

NAT и общие IP

В школах, общежитиях и интернет-кафе несколько игроков сидят за одним IP. connlimit с порогом 3 заблокирует четвертого игрока. Решения:

  • Поднимите connlimit до 10-15 для таких случаев
  • Используйте вайтлист для известных IP учреждений
  • Опирайтесь больше на hashlimit (скорость), чем на connlimit (количество)

Игроки на мобильном интернете

Мобильный интернет часто меняет IP, и игрок может попасть на IP, с которого недавно был бот. Если вы используете долгие блокировки (30 минут и больше), мобильный игрок может оказаться заблокирован "по наследству".

Решение: используйте короткие TTL для блокировок. 60-120 секунд достаточно, чтобы остановить активную атаку, но не заблокировать случайного мобильного игрока.

Whitelisting: доверенные IP

Некоторые IP-адреса никогда не должны попадать под rate limiting:

# Прокси-серверы сети
iptables -I INPUT -p tcp --dport 25565 -s 10.0.0.1 -j ACCEPT
iptables -I INPUT -p tcp --dport 25565 -s 10.0.0.2 -j ACCEPT

# Мониторинг (uptime check)
iptables -I INPUT -p tcp --dport 25565 -s 1.2.3.4 -j ACCEPT

Правила с -I (insert) добавляются в начало цепочки и обрабатываются до rate limiting правил. Это критично: если ваш прокси-сервер попадет под hashlimit, все игроки потеряют связь.

В Velocity/BungeeCord вайтлист обычно не нужен, потому что rate limiting применяется к внешним подключениям, а backend-серверы общаются через внутреннюю сеть.

Rate limiting по слоям

Самая эффективная стратегия - rate limiting на каждом уровне с разной логикой:

Сетевой уровень (iptables)

Что ограничивать: TCP SYN-пакеты, одновременные соединения.

Цель: отсечь грубый connection flood до того, как пакеты дойдут до Java.

# SYN flood protection
iptables -A INPUT -p tcp --dport 25565 --syn \
  -m hashlimit --hashlimit-above 10/sec \
  --hashlimit-burst 20 --hashlimit-name mc_syn \
  --hashlimit-mode srcip -j DROP

Прокси-уровень (Velocity)

Что ограничивать: Minecraft login-попытки, повторные подключения.

Цель: отсечь ботов, которые прошли TCP handshake, но не являются настоящими игроками.

# velocity.toml
[advanced]
login-ratelimit = 3000

Уровень приложения (плагины)

Что ограничивать: действия в игре (команды, чат, взаимодействие).

Цель: отсечь ботов, которые прошли login, но ведут себя аномально.

# paper-global.yml
packet-limiter:
  limits:
    ServerboundCommandSuggestionPacket:
      interval: 1.0
      max-packet-rate: 15.0

Каждый уровень ловит свой тип угрозы. iptables останавливает SYN flood. Velocity останавливает connection spam. Плагины останавливают packet abuse.

Rate limiting и DDoS-защита

Rate limiting - это часть DDoS-защиты, но не вся защита. Против серьезной DDoS-атаки (десятки гигабит трафика) rate limiting на сервере бесполезен: канал забит, пакеты не доходят.

Для серьезной защиты нужна фильтрация на уровне сети до вашего сервера. MineGuard фильтрует трафик на уровне сети, отбрасывая мусорные пакеты до того, как они дойдут до вашего сервера. Rate limiting на сервере работает как второй эшелон: ловит то, что прошло через сетевой фильтр.

Вместе они создают эшелонированную защиту:

  1. DDoS-фильтр (MineGuard) - останавливает объемные атаки на сетевом уровне
  2. iptables rate limiting - ограничивает скорость соединений, прошедших фильтр
  3. Proxy rate limiting - фильтрует на уровне Minecraft-протокола
  4. Plugin rate limiting - защищает от злоупотреблений внутри игры

Подробнее о бот-атаках и методах защиты в нашей статье о бот-атаках на Minecraft.

Мониторинг эффективности

Rate limiting бесполезен, если вы не знаете, работает ли он. Вот что стоит мониторить:

iptables counters

# Показать счётчики правил
iptables -L -n -v | grep hashlimit

Каждое правило iptables имеет счетчик пакетов и байт. Если ваше hashlimit правило показывает тысячи дропов, значит оно работает. Если ноль - либо атак нет, либо правило не срабатывает (проверьте порядок правил).

Логирование заблокированных

# Логировать перед дропом (ограничить логирование, чтобы не забить диск)
iptables -A INPUT -p tcp --dport 25565 --syn \
  -m hashlimit --hashlimit-above 10/sec \
  --hashlimit-burst 20 --hashlimit-name mc_syn \
  --hashlimit-mode srcip \
  -m limit --limit 5/min \
  -j LOG --log-prefix "MC_RATELIMIT: "

iptables -A INPUT -p tcp --dport 25565 --syn \
  -m hashlimit --hashlimit-above 10/sec \
  --hashlimit-burst 20 --hashlimit-name mc_syn \
  --hashlimit-mode srcip \
  -j DROP

Обратите внимание на -m limit --limit 5/min в правиле LOG. Без этого при активной атаке логирование само может стать проблемой: тысячи записей в секунду убьют диск и загрузят CPU.

Velocity статистика

Velocity логирует throttled-подключения в stdout:

[INFO] [ratelimiter] Connection from 1.2.3.4 throttled

Парсите эти логи для мониторинга. Если видите массовый throttle с разных IP - это бот-атака. Если с одного IP - один упорный бот или игрок с проблемным соединением.

Практическая шпаргалка

Минимальная настройка rate limiting для Minecraft сервера:

iptables (выполнить на сервере):

# Вайтлист для прокси (если есть)
iptables -I INPUT -p tcp --dport 25565 -s YOUR_PROXY_IP -j ACCEPT

# Лимит одновременных соединений
iptables -A INPUT -p tcp --dport 25565 \
  -m connlimit --connlimit-above 5 -j DROP

# Лимит скорости новых подключений
iptables -A INPUT -p tcp --dport 25565 --syn \
  -m hashlimit --hashlimit-name mc \
  --hashlimit-above 10/sec --hashlimit-burst 25 \
  --hashlimit-mode srcip -j DROP

Velocity:

[advanced]
login-ratelimit = 3000

Paper:

packet-limiter:
  limits:
    all:
      interval: 7.0
      max-packet-rate: 500.0

Этого достаточно для базовой защиты. Дальше настраивайте пороги под вашу нагрузку: мониторьте счетчики, смотрите логи, корректируйте значения.

Частые ошибки

Слишком низкий connlimit. connlimit: 1 заблокирует игрока, который переподключается (старое соединение еще висит в TIME_WAIT). Минимум 3.

Забытый вайтлист. Прокси-сервер попадает под rate limit, и все игроки теряют соединение. Всегда добавляйте прокси в вайтлист.

Нет burst. hashlimit без burst блокирует любой кратковременный всплеск. Игрок зашел, вылетел, зашел снова - заблокирован. Burst 15-25 решает проблему.

Rate limit на ESTABLISHED. Применяйте rate limiting только к новым соединениям (--syn), иначе вы ограничите трафик уже подключенных игроков.

Глобальный лимит без per-IP. Глобальный лимит "100 подключений в секунду на весь сервер" заблокирует всех, когда один IP генерирует 100 подключений. Всегда используйте per-IP лимиты.

Rate limiting - не серебряная пуля. Это один слой в многослойной защите. Но без него остальные слои работают хуже. Настройте базовые лимиты, мониторьте их эффективность, и корректируйте по мере необходимости.

Глобальный vs per-IP rate limiting

Важное различие, которое многие упускают. Глобальный rate limiter ограничивает общее число подключений ко всему серверу. Per-IP rate limiter считает подключения отдельно для каждого IP-адреса.

Глобальный лимит полезен как "аварийный тормоз". Если ваш сервер рассчитан на 200 игроков, нет смысла принимать 10000 соединений в секунду. Глобальный лимит в 500-1000 соединений в секунду защитит от ситуации, когда атака идет с тысяч разных IP (каждый шлет по 1-2 соединения, и per-IP лимит не срабатывает).

Пример реализации глобального лимита:

# Глобальный лимит: не больше 200 новых соединений в секунду на весь сервер
iptables -A INPUT -p tcp --dport 25565 --syn \
  -m hashlimit \
  --hashlimit-name mc_global \
  --hashlimit-above 200/sec \
  --hashlimit-burst 300 \
  --hashlimit-mode dstip \
  -j DROP

Ключевое отличие: --hashlimit-mode dstip вместо srcip. Теперь iptables считает все подключения к нашему IP, а не от каждого отдельного источника.

Комбинация обоих типов дает максимальную защиту:

  1. Per-IP лимит ловит ботов, которые спамят с одного адреса
  2. Глобальный лимит ловит распределенные атаки с тысяч IP

Автоматическая адаптация лимитов

Статические лимиты работают, но не идеальны. На пустом сервере ночью 10 подключений в секунду с одного IP - явно бот. В субботу вечером, когда онлайн 300 человек, пиковая нагрузка может быть нормой.

Простой подход к динамическому rate limiting:

#!/bin/bash
# adaptive-ratelimit.sh
# Запускать через cron каждые 5 минут

CURRENT_PLAYERS=$(screen -S minecraft -p 0 -X stuff "list\n" 2>/dev/null; sleep 1; grep -c "players online" /path/to/latest.log)

if [ "$CURRENT_PLAYERS" -gt 200 ]; then
    # Высокий онлайн - ослабить лимиты
    RATE=20
    BURST=40
elif [ "$CURRENT_PLAYERS" -gt 50 ]; then
    # Средний онлайн
    RATE=15
    BURST=30
else
    # Низкий онлайн - строгие лимиты
    RATE=8
    BURST=15
fi

# Обновить правила (удалить старое, добавить новое)
iptables -D INPUT -p tcp --dport 25565 --syn \
  -m hashlimit --hashlimit-name mc_adaptive \
  --hashlimit-above ${RATE}/sec --hashlimit-burst ${BURST} \
  --hashlimit-mode srcip -j DROP 2>/dev/null

iptables -A INPUT -p tcp --dport 25565 --syn \
  -m hashlimit --hashlimit-name mc_adaptive \
  --hashlimit-above ${RATE}/sec --hashlimit-burst ${BURST} \
  --hashlimit-mode srcip -j DROP

Это базовый пример. В продакшене лучше использовать fail2ban или собственный демон, который анализирует логи в реальном времени и корректирует правила.

GeoIP и rate limiting

Если 95% ваших игроков из России и СНГ, а бот-атака идет с IP-адресов из Бразилии и Индонезии, можно применить более строгий rate limiting для определенных стран:

# Установить модуль geoip для iptables
# На Ubuntu/Debian: apt install xtables-addons-common

# Строгий лимит для не-CIS стран
iptables -A INPUT -p tcp --dport 25565 --syn \
  -m geoip ! --src-cc RU,UA,KZ,BY \
  -m hashlimit --hashlimit-name mc_foreign \
  --hashlimit-above 3/sec --hashlimit-burst 5 \
  --hashlimit-mode srcip -j DROP

Осторожно с этим подходом: GeoIP базы не идеальны, и вы можете заблокировать игроков, которые используют VPN для снижения пинга. Используйте как дополнительный фильтр, а не как основной.


Sunucunuzu DDoS Saldırılarından Koruyun

5 dakikada kurulumla ücretsiz koruma. 1 TB bant genişliği dahil.

Ücretsiz Deneyin


İlgili Makaleler