RE:NODE

Безопасность13 мин чтения

Правила файрвола, которые важны, и те, которые нет

Запрет по умолчанию, короткий список разрешений и три порта, которые оставляют открытыми сами того не замечая. С правилами ufw и nftables для копирования и командами аудита.

Обновлено

0 прочтений

Файрвол - это список того, что разрешено, а всё остальное отклоняется. В такой формулировке звучит тривиально, и набор правил, защищающий настоящий сервер, действительно короткий: один-два публичных порта, административный доступ только с подконтрольных вам адресов и ничего больше.

Ошибка почти никогда не в недостающем правиле. Это правило, добавленное в три часа ночи во время отладки и так и не удалённое, или служба, которая не должна была слушать на публичном интерфейсе и тихо это делает. В этой статье - набор правил, который стоит иметь, в ufw и в nftables, порты, которые остаются открытыми без чьего-либо решения, причина, по которой Docker вообще игнорирует ваш файрвол, и что всё это значит, когда сервер работает на чужой панели, а не на вашей машине.

Что делает файрвол и как выглядит набор правил, который выдерживает#

Файрвол хоста решает для каждого пакета, передавать ли его ядром слушающему процессу. Работа узкая, и стоит ясно понимать, что остаётся за её пределами.

Он не останавливает объёмный флуд. К моменту, когда пакет доходит до вашей машины, он уже пересёк ваш аплинк, поэтому локальный сброс не освобождает канал, который тот занял. Фильтрация крупных потоков должна происходить выше по цепочке: что мы делаем с атаками - честный рассказ о том, что это ловит, а типы атак разобраны в статье DDoS-атаки на игровые серверы простыми словами. Он не помогает против трафика, неотличимого от игрока, потому что на уровне пакетов это и есть игрок. И он ничего не делает со слабым паролем, непропатченным плагином или вредоносным модом - именно так серверы в основном и теряют.

Зато он сводит открытую поверхность к двум-трём вещам, которые вы публикуете намеренно. Это очень много, и занимает около десяти минут.

Скелет состоит из пяти правил, именно в таком порядке:

  1. Принимать установленный и связанный трафик. Отслеживание соединений позволяет ответам на соединения, которые вы открыли, проходить без отдельного правила для каждого. Без этого политика запрета по умолчанию блокирует ответ на каждый запрос, который делает ваш сервер.
  2. Отбрасывать некорректные пакеты. Трафик, не принадлежащий ни одному отслеживаемому соединению и не являющийся законным новым.
  3. Принимать всё на loopback. Локальные службы общаются друг с другом через 127.0.0.1 и ::1. Блокировка этого ломает вещи запутанными способами.
  4. Разрешить нужный ICMP. Эхо-запросы, чтобы вас можно было пинговать, и, что критично, сообщения, на которых держится path MTU discovery. Слепой сброс ICMPv6 просто ломает IPv6; почему так, описано в статье IPv6 и игровые серверы.
  5. Затем короткий список разрешений и запрет всего остального по умолчанию.
что прошлотолько разрешённые портыпохоже на игрокаИнтернетчто угодноФильтрация вышеобъёмный флудФайрвол хостазапрет по умолчаниюПравила контейнераопубликованные портыИгровой серверслушающий сокетПриложениепароли, лимиты
Что решает, дойдёт ли пакет до игры

Правила по портам#

Каждое правило отвечает на три вопроса: какой порт, какой протокол и для кого открыто. Третий пропускают чаще всего, и он важнее всего.

ПортПротоколОткрыт дляЧто это
22TCPТолько ваши адресаSSH
80, 443TCPВсехВеб-трафик
25565TCPВсехMinecraft Java
19132UDPВсехMinecraft Bedrock или Geyser
27015UDPВсехИгра и запросы на движке Source
2456-2457UDPВсехИгра и запросы Valheim
25575TCPНикого или один адресRCON Minecraft
5432TCPТолько приложениеPostgreSQL
27017TCPТолько приложениеMongoDB
6379TCPТолько loopbackRedis
9200TCPТолько loopbackElasticsearch и родственные
8080, 3000TCPНикогоВсё, что вы привязали при тестировании

Две строки заслуживают пояснения. Порты запросов должны быть открыты, иначе сервер прекрасно работает и никогда не появляется ни в чьём списке, а такая неисправность совсем не похожа на проблему файрвола; почему так, описано в статье порты игровых серверов простыми словами. А RCON Source - это TCP на том же номере порта, который игра использует по UDP, то есть разделить их только по номеру нельзя: правило должно различать протоколы.

У «для кого открыто» три полезных значения. Для всех - для службы, которую вы действительно публикуете. Конкретный адрес или префикс - для администрирования. И только loopback, что вовсе не правило файрвола, а решение о привязке в конфигурации самой службы, и оно всегда лучше правила файрвола, когда доступно.

Запись правил через ufw#

ufw - надстройка над iptables, которая превращает типовой набор правил в четыре команды. В Debian и Ubuntu он обычно уже установлен.

bash
$ ufw default deny incoming$ ufw default allow outgoing$ ufw allow from 203.0.113.5 to any port 22 proto tcp comment 'ssh admin'$ ufw allow 25565/tcp comment 'minecraft java'$ ufw allow 2456:2457/udp comment 'valheim game and query'$ ufw enable

Несколько замечаний об этой последовательности:

  • Добавьте правило для SSH до включения. Включение политики запрета по умолчанию поверх SSH без правила для SSH запирает вас снаружи машины, и вернуться можно только через консоль в панели вашего провайдера.
  • Диапазону портов нужен протокол. ufw allow 2456:2457/udp допустимо, ufw allow 2456:2457 - нет.
  • Используйте `comment`. Через полгода правило, которое вы не можете объяснить, вы оставите из страха. Комментарий превращает это в решение.
  • `ufw limit 22/tcp` разрешает SSH, но ограничивает адрес, делающий больше шести соединений за тридцать секунд. Полезно, если SSH приходится открывать всему миру, чего лучше избегать.
  • IPv6 - отдельный набор правил, и ufw управляет им только при IPV6=yes в /etc/default/ufw. В современных установках это включено по умолчанию, но проверить всё равно стоит.

Потом прочитайте, что вы построили, потому что список и есть документация:

bash
$ ufw status numberedStatus: active     To                         Action      From     --                         ------      ----[ 1] 22/tcp                     ALLOW IN    203.0.113.5     # ssh admin[ 2] 25565/tcp                  ALLOW IN    Anywhere        # minecraft java[ 3] 2456:2457/udp              ALLOW IN    Anywhere        # valheim$ ufw delete 3

Включите журналирование через ufw logging low, и отклонённые пакеты попадут в /var/log/ufw.log. Шума много - интернет постоянно сканирует каждый адрес, - но именно так вы узнаёте, что то, что должно работать, блокируется. Инструмент подробно разобран в руководстве по ufw, а первый час на новом VDS ставит его в тот порядок, которого требует остальная настройка.

Те же правила в nftables#

Если вы строите то, что будете поддерживать годами, nftables - основа получше. Одна таблица inet покрывает IPv4 и IPv6 в одном наборе правил, что убирает целый класс ошибок вида «на v4 работает, на v6 молча отбрасывается».

/etc/nftables.conf
#!/usr/sbin/nft -fflush rulesettable inet filter {  chain input {    type filter hook input priority filter; policy drop;    ct state established,related accept    ct state invalid drop    iif lo accept    ip protocol icmp icmp type { echo-request, destination-unreachable, time-exceeded } accept    ip6 nexthdr icmpv6 accept    tcp dport 22 ip saddr 203.0.113.5 accept    tcp dport { 80, 443 } accept    tcp dport 25565 accept    udp dport 2456-2457 accept  }  chain forward { type filter hook forward priority filter; policy drop; }  chain output  { type filter hook output  priority filter; policy accept; }}

Загрузите его командой nft -f /etc/nftables.conf и проверьте через nft list ruleset. Включите nftables.service, чтобы набор пережил перезагрузку, и проверьте правила из второй сессии, прежде чем закрывать ту, в которой работаете.

Docker и почему ваши правила игнорируются#

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

Причина в том, что Docker пишет собственные правила прямо в iptables, в таблицу nat и в цепочки, которые просматриваются раньше тех, чем управляет ufw. Публикация порта через -p 5432:5432 настраивает destination NAT, который целиком обходит цепочку INPUT. Ваш файрвол не сломан, его просто не спрашивают.

Выходов три, и пользоваться нужно первым:

  1. Публикуйте на loopback. -p 127.0.0.1:5432:5432 привязывает опубликованный порт только к локальному интерфейсу, так что контейнер доступен с хоста и больше ниоткуда. В файле Compose это "127.0.0.1:5432:5432".
  2. Пишите правила в цепочке `DOCKER-USER`, которую Docker просматривает раньше своих и не перезаписывает. Это работает, но легко ошибиться, потому что пакеты уже прошли через NAT и адреса не те, которых вы ждёте.
  3. Не публикуйте порт вообще. Контейнеры в одной сети Docker обращаются друг к другу по имени на порту контейнера. Если с базой данных общается только ваше приложение, опубликованный порт ей не нужен совсем.

Остальная настройка описана в статье Docker на VDS, и то же рассуждение применимо к любой среде контейнеров, управляющей собственной сетью.

Порты, которые оставляют открытыми, и как их найти#

Три из них встречаются снова и снова, и все три открыл разумный человек по разумной причине.

Порт базы данных, открытый, чтобы проверить подключение из дома. Postgres на 5432 и MongoDB на 27017 открывают на десять минут, чтобы выполнить запрос из настольного клиента, и они так и остаются открытыми. Для Postgres файрвол - лишь половина контроля: listen_addresses в postgresql.conf решает, к каким интерфейсам он привязывается, а pg_hba.conf решает, кто и как может аутентифицироваться. Строка вроде host all all 0.0.0.0/0 md5 в pg_hba.conf - настоящая дверь, а закрытие файрвола при сохранённой строке - исправление, которое живёт ровно столько, сколько правило файрвола. Весь список - в чек-листе безопасности базы данных, а безопасный способ описан в статье удалённое подключение к PostgreSQL.

Порт RCON, открытый для инструмента, удалённого год назад. RCON придумали в более доверчивую эпоху: в большинстве реализаций пароль ходит по сети почти без защиты, и тот, кто его знает, может всё, что может консоль. Если у вас есть консоль в панели, открытый RCON вам вообще не нужен - подробно об этом в статье безопасная работа с RCON.

Интерфейс администрирования или отладки, привязанный ко всем интерфейсам, потому что так было по умолчанию. Веб-админка на 8080, эндпоинт метрик на 9090, сервер разработки на 3000, профилировщик, оставленный после расследования. Массовые сканеры находят их через часы после открытия, а не через дни.

Найти их можно двумя командами. С самой машины:

bash
$ ss -ltnp$ ss -lunp

Всё, что привязано к 0.0.0.0 или [::], слушает на всех интерфейсах. Всё на 127.0.0.1 доступно только локально и вас не касается. Пройдите по списку и вслух обоснуйте каждую запись.

Затем проверьте снаружи, потому что то, что машина считает, и то, что доступно из интернета, - разные вопросы:

bash
$ nmap -Pn -p- --open node.example.com$ nmap -Pn -sU --top-ports 50 node.example.com

Сканируйте только свои серверы. UDP-сканирование медленное и по природе протокола менее надёжное, чем TCP, и поэтому же UDP-службы так часто забывают.

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

Исходящий трафик: правила, которые никто не пишет#

Почти любой набор правил разрешает весь исходящий трафик, и для большинства серверов это верное решение. Но стоит знать, что вы принимаете.

Скомпрометированный процесс - вредоносный мод, плагин с форума, зависимость с бэкдором - использует исходящие соединения для всего, что идёт дальше: скачать второй этап, вступить в ботнет, отправить ваши данные куда-то или рассылать спам. Входящая сторона вашего файрвола тут вообще ни при чём.

Два правила для исходящего дёшевы и полезны почти на любом сервере:

  • Блокируйте исходящий TCP 25. Ничто на игровом или прикладном сервере не отправляет почту напрямую на законных основаниях. Это правило превращает «наша машина рассылала спам, и наш адрес попал в блок-лист» в строчку журнала.
  • Блокируйте исходящие соединения из контейнера с базой данных, если он у вас есть. У базы нет дел с интернетом, и если она начинает туда ходить, вы хотите об этом знать.

Полная белая список-фильтрация исходящих - перечисление всех адресов назначения, куда серверу можно ходить, - реалистична для «прибора» и мучительна для игрового сервера, где моды скачиваются с десятка хостов, о которых вы не слышали. Судите по тому, что делает сервер. Если обновление мода ломается, потому что не достучалось до CDN, правила стоят дороже, чем сберегли; шире этот компромисс разобран в статье как держать модифицированный сервер в чистоте.

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

На панели файрвол вам не принадлежит#

Если сервер работает на управляемой панели, а не на вашей машине, ничто из материала про ufw и nftables выше вас не касается, и это в основном хорошая новость: те части работы, на которых людей взламывают, уже решены и не могут быть случайно отредактированы.

Чем вы управляете вместо этого:

  • Какие порты существуют. Каждый тариф называет свои выделения, порты добавляются и убираются на вкладке Network сервера, включая запросы и RCON. Порт, который не выделен, недоступен, - это правило файрвола, выраженное списком, читаемым с первого взгляда.
  • Изоляция. Один контейнер на сервер, CPU как жёсткое ограничение до купленной доли. Ваши соседи не на вашей машине ни в каком значимом смысле.
  • Консоль вместо RCON. Консоль панели - та же возможность за аккаунтом, который вы и так защищаете как следует, а не второй пароль на открытом порту.
  • Безопасность аккаунта, которая теперь и есть настоящий периметр. Двухфакторная аутентификация TOTP с одноразовыми кодами восстановления, хеши паролей bcrypt, captcha и ограничения частоты при входе, список сессий, из которых можно выйти, и API-ключи, которые можно ограничить по адресу. Двухфакторная аутентификация в аккаунте панели - пять минут потраченные с пользой.
  • Минимальные привилегии для людей. Субпользователи, роли и команды с детальными правами - только консоль, только файлы, без биллинга, - доступ на ограниченное время и журнал действий по каждому серверу. Это контроль, который важен, когда доступ есть больше чем у одного человека, и он описан в статье субпользователи и минимальные привилегии.

Секреты - вторая половина периметра и нередко самая слабая: пароль от базы в публичном репозитории отменяет все правила выше. Как держать их подальше от мест, куда смотрят в первую очередь, описано в статье переменные окружения и секреты.

Если вам нужен полный файрвол, это довод в пользу VDS, вместе со всем остальным, что вам тогда придётся поддерживать самим; честное сравнение - в статье VDS или игровая панель: как выбрать.

FAQ#

Нужен ли файрвол, если на сервере запущена только одна игра?

Если это ваша собственная машина, да. Игровой сервер редко работает один: SSH, службы менеджера пакетов, агент мониторинга и всё, что вы установили для отладки в прошлом месяце, - всё это слушает. Запрет по умолчанию делает так, что список открытых служб совпадает со списком тех, что вы задумывали.

Защищает ли файрвол от DDoS-атак?

Нет. Отброшенный пакет уже потратил вашу пропускную способность, так что файрвол хоста не помогает против потока, забивающего канал. Фильтрация трафика такого размера происходит выше по цепочке от машины, и даже там различимы только очевидный объёмный и отражённый трафик.

Стоит ли менять порт SSH с 22?

Это снижает шум в журнале от автоматических сканеров, но безопасностью не является. Важны аутентификация только по ключам с PasswordAuthentication no, ограничение порта адресами, которые вы контролируете, и fail2ban сверху. Смена порта необязательна и никак не влияет на то, кто получит доступ.

Почему до моего контейнера можно достучаться, хотя ufw всё запрещает?

Потому что Docker пишет собственные правила iptables, которые просматриваются раньше цепочек, управляемых ufw, и опубликованный порт обходит вашу политику. Публикуйте на 127.0.0.1 вместо всех интерфейсов либо не публикуйте порт вообще, если он нужен только другому контейнеру.

Как часто пересматривать правила файрвола?

Раз в квартал, а также после каждого инцидента или миграции. Пересмотр короткий: выведите правила, выведите то, что реально слушает, через ss -ltnp и удалите всё, что не можете обосновать одним предложением. Набор правил почти всегда становится короче.


Комментарии

Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.

0/2000