Firewall

Firewall — межсетевой экран, который контролирует сетевой трафик по заданным правилам.

Firewall может разрешать или блокировать соединения на основе:

Простейшее правило можно описать так:

Разрешить входящие TCP-соединения на порт 443.

Или:

Запретить входящие соединения с IP-адреса 203.0.113.50.

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

Firewall не заменяет:

Он ограничивает сетевую доступность, но не устраняет уязвимости уже разрешённого сервиса.


Stateful и stateless firewall

Stateless firewall

Stateless firewall рассматривает каждый пакет независимо.

Для каждого пакета проверяются:

Такой firewall не помнит, является ли пакет частью уже установленного соединения.

Stateful firewall

Stateful firewall отслеживает состояние соединений.

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

Для TCP firewall может отслеживать состояния:

NEW
ESTABLISHED
RELATED
INVALID

На Linux состояние соединений отслеживается подсистемой conntrack.

Типичное правило:

Разрешить уже установленные и связанные соединения.

Это позволяет не описывать отдельное правило для каждого ответного пакета.


Основные действия правил

Правило firewall обычно заканчивается действием.

ACCEPT

Разрешает пакет или соединение:

ACCEPT

Пример:

Разрешить TCP-порт 443.

DROP

Молча отбрасывает пакет:

DROP

Отправитель обычно не получает ответа. Это увеличивает время ожидания соединения.

REJECT

Отклоняет пакет и обычно отправляет сообщение об ошибке:

REJECT

Клиент быстрее узнаёт, что соединение запрещено.

Разница:

DROP   — не отвечать;
REJECT — явно отказать.

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

LOG

Записывает информацию о пакете в журнал:

LOG

Логирование следует использовать осторожно. Если правило вызывается для большого количества пакетов, журналы могут быстро заполнить диск.

RETURN

Возвращает обработку из пользовательской цепочки в вызывающую цепочку:

RETURN

Принцип обработки правил

Правила обычно проверяются сверху вниз.

Если пакет совпал с правилом, выполняется его действие:

1. Разрешить TCP 22 с доверенного IP
2. Запретить TCP 22 от остальных

Пакет от доверенного IP совпадёт с первым правилом и будет разрешён.

Если поменять порядок:

1. Запретить TCP 22 от всех
2. Разрешить TCP 22 с доверенного IP

второе правило может никогда не сработать.

Поэтому порядок правил имеет значение.

Типичная последовательность:

  1. разрешить loopback;
  2. разрешить уже установленные соединения;
  3. разрешить явно нужные сервисы;
  4. добавить специальные исключения;
  5. запретить остальной трафик.

iptables

iptables — классический инструмент настройки firewall в Linux.

В современных системах команда iptables может работать поверх совместимого backend на базе nftables, но синтаксис при этом остаётся старым.

Проверить версию:

iptables --version

Пример возможного вывода:

iptables v1.8.x (nf_tables)

Это означает, что команда iptables использует backend nftables.

На новых системах предпочтительнее использовать непосредственно nftables или управляющий инструмент дистрибутива.


Таблицы iptables

iptables разделяет правила по таблицам.

filter

Основная таблица фильтрации пакетов.

Используется для:

nat

Таблица трансляции адресов и портов.

Используется для:

mangle

Используется для специальных изменений и маркировки пакетов.

raw

Используется для обработки пакетов до некоторых этапов conntrack.

В обычной настройке веб-сервера чаще всего работают с таблицей:

filter

а при публикации сервисов через NAT — дополнительно с:

nat

Цепочки iptables

В таблице filter есть стандартные цепочки:

INPUT
OUTPUT
FORWARD

INPUT

Обрабатывает пакеты, предназначенные для текущего хоста:

Интернет → сервер

Например, входящее подключение к порту 443.

OUTPUT

Обрабатывает пакеты, созданные текущим хостом:

Сервер → Интернет

Например, запрос сервера к DNS или внешнему API.

FORWARD

Обрабатывает пакеты, которые проходят через хост, но предназначены не ему.

Цепочка используется, если Linux работает как:


Пользовательские цепочки

Можно создавать собственные цепочки:

iptables -N WEB_RULES

Переход в пользовательскую цепочку:

iptables -A INPUT -p tcp --dport 443 -j WEB_RULES

Пользовательские цепочки позволяют разделять большие наборы правил по назначению.


Просмотр правил iptables

sudo iptables -L

Более подробный вывод:

sudo iptables -L -n -v

Параметры:

С номерами правил:

sudo iptables -L --line-numbers -n -v

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

sudo iptables-save

Для IPv6:

sudo ip6tables -L -n -v

Установка политик по умолчанию

sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

Здесь:

Перед установкой политики DROP необходимо добавить правила для управления сервером. Иначе можно потерять SSH-доступ.


Loopback-интерфейс

Локальные программы используют интерфейс:

lo

Разрешение loopback-трафика:

sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

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


Уже установленные соединения

Разрешение существующих и связанных соединений:

sudo iptables -A INPUT -m conntrack \
  --ctstate ESTABLISHED,RELATED \
  -j ACCEPT

Для исходящего трафика:

sudo iptables -A OUTPUT -m conntrack \
  --ctstate ESTABLISHED,RELATED \
  -j ACCEPT

Смысл правила:

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

Разрешение TCP-порта

Разрешить SSH:

sudo iptables -A INPUT \
  -p tcp \
  --dport 22 \
  -m conntrack --ctstate NEW \
  -j ACCEPT

Разрешить HTTP:

sudo iptables -A INPUT \
  -p tcp \
  --dport 80 \
  -m conntrack --ctstate NEW \
  -j ACCEPT

Разрешить HTTPS:

sudo iptables -A INPUT \
  -p tcp \
  --dport 443 \
  -m conntrack --ctstate NEW \
  -j ACCEPT

Можно использовать короткую форму без проверки состояния:

sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

Однако явное указание состояния делает назначение правила понятнее.


Разрешение UDP-порта

Разрешить DNS-запросы к серверу:

sudo iptables -A INPUT \
  -p udp \
  --dport 53 \
  -m conntrack --ctstate NEW \
  -j ACCEPT

Если DNS-сервер также принимает TCP-запросы:

sudo iptables -A INPUT \
  -p tcp \
  --dport 53 \
  -m conntrack --ctstate NEW \
  -j ACCEPT

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


Ограничение по IP-адресу

Разрешить SSH только с доверенного адреса:

sudo iptables -A INPUT \
  -p tcp \
  -s 198.51.100.25 \
  --dport 22 \
  -j ACCEPT

Запретить соединения с адреса:

sudo iptables -A INPUT \
  -s 203.0.113.50 \
  -j DROP

Разрешить доступ к веб-серверу только из подсети:

sudo iptables -A INPUT \
  -p tcp \
  -s 198.51.100.0/24 \
  --dport 443 \
  -j ACCEPT

Ограничение по интерфейсу

Разрешить трафик на конкретном интерфейсе:

sudo iptables -A INPUT \
  -i eth0 \
  -p tcp \
  --dport 443 \
  -j ACCEPT

Для VPN-интерфейса:

sudo iptables -A INPUT \
  -i wg0 \
  -p tcp \
  --dport 8080 \
  -j ACCEPT

ICMP

ICMP используется для диагностических и служебных сообщений.

Разрешение входящих ICMP-пакетов:

sudo iptables -A INPUT -p icmp -j ACCEPT

Более строгие правила могут разрешать только определённые типы ICMP.

Для IPv4 можно, например, разрешить echo request:

sudo iptables -A INPUT \
  -p icmp \
  --icmp-type echo-request \
  -j ACCEPT

Для IPv6 ICMPv6 особенно важен. Он используется не только для ping, но и для:

Полная блокировка ICMPv6 может нарушить IPv6-соединения.


Политика по умолчанию и явный запрет

Вариант с политикой по умолчанию:

sudo iptables -P INPUT DROP

Остальной неподходящий трафик будет запрещён автоматически.

Можно добавить явное правило:

sudo iptables -A INPUT -j DROP

Обычно достаточно одного подхода. Явный финальный DROP может быть удобен, если в конце цепочки нужно добавить логирование:

sudo iptables -A INPUT \
  -m limit --limit 5/min \
  -j LOG --log-prefix "iptables-input-drop: "

sudo iptables -A INPUT -j DROP

Ограничение --limit предотвращает чрезмерное количество записей в журнале.


nftables

nftables — современная подсистема фильтрации и трансляции сетевого трафика в Linux.

Преимущества nftables:

Основная команда:

sudo nft

Проверить версию:

nft --version

Семейства nftables

nftables группирует правила по семействам.

ip

Только IPv4:

ip

ip6

Только IPv6:

ip6

inet

IPv4 и IPv6:

inet

Для обычного firewall сервера часто удобно использовать:

table inet filter

bridge

Фильтрация bridge-трафика.

netdev

Фильтрация на уровне сетевого устройства.


Просмотр текущей конфигурации

sudo nft list ruleset

Счётчики и подробная информация:

sudo nft -a list ruleset

Таблица и цепочки nftables

Создание таблицы:

sudo nft add table inet filter

Создание цепочки для входящего трафика:

sudo nft add chain inet filter input \
  '{ type filter hook input priority 0; policy drop; }'

Создание цепочки для исходящего трафика:

sudo nft add chain inet filter output \
  '{ type filter hook output priority 0; policy accept; }'

Создание цепочки для маршрутизируемого трафика:

sudo nft add chain inet filter forward \
  '{ type filter hook forward priority 0; policy drop; }'

Loopback в nftables

sudo nft add rule inet filter input iifname "lo" accept

Уже установленные соединения

sudo nft add rule inet filter input \
  ct state established,related accept

Невалидные пакеты можно явно отклонять:

sudo nft add rule inet filter input \
  ct state invalid drop

Разрешение TCP-портов

Разрешить SSH:

sudo nft add rule inet filter input \
  tcp dport 22 \
  ct state new accept

Разрешить HTTP и HTTPS:

sudo nft add rule inet filter input \
  tcp dport { 80, 443 } \
  ct state new accept

В nftables фигурные скобки задают набор значений.


Разрешение UDP-портов

sudo nft add rule inet filter input \
  udp dport 53 \
  ct state new accept

Несколько UDP-портов:

sudo nft add rule inet filter input \
  udp dport { 53, 51820 } \
  ct state new accept

Ограничение по IP-адресу

sudo nft add rule inet filter input \
  ip saddr 198.51.100.25 \
  tcp dport 22 \
  accept

Для IPv6:

sudo nft add rule inet filter input \
  ip6 saddr 2001:db8:1234::/48 \
  tcp dport 22 \
  accept

Семейство inet позволяет использовать IPv4- и IPv6-правила в одной таблице.


Разрешение ICMP и ICMPv6

sudo nft add rule inet filter input \
  meta l4proto icmp accept

sudo nft add rule inet filter input \
  meta l4proto icmpv6 accept

Для рабочего сервера правила ICMP и ICMPv6 лучше адаптировать под конкретную сетевую политику, а не бездумно разрешать или запрещать весь протокол.


Пример базовой конфигурации nftables

#!/usr/sbin/nft -f

flush ruleset

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

        # Локальный трафик
        iifname "lo" accept

        # Уже установленные соединения
        ct state established,related accept

        # Некорректные пакеты
        ct state invalid drop

        # ICMP и ICMPv6
        meta l4proto icmp accept
        meta l4proto icmpv6 accept

        # SSH
        tcp dport 22 ct state new accept

        # HTTP и HTTPS
        tcp dport { 80, 443 } ct state new accept
    }

    chain forward {
        type filter hook forward priority 0;
        policy drop;
    }

    chain output {
        type filter hook output priority 0;
        policy accept;
    }
}

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


Сохранение конфигурации nftables

Расположение файла зависит от дистрибутива. Часто используется:

/etc/nftables.conf

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

sudo nft -c -f /etc/nftables.conf

Загрузить конфигурацию:

sudo nft -f /etc/nftables.conf

Включить запуск при загрузке:

sudo systemctl enable nftables
sudo systemctl start nftables

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

sudo nft -c -f /etc/nftables.conf

Синтаксическая ошибка в конфигурации может привести к тому, что firewall не загрузится после перезагрузки.


iptables и nftables

iptables и nftables могут сосуществовать, но одновременное управление одним и тем же трафиком разными инструментами усложняет диагностику.

Нужно определить, какой механизм используется:

iptables --version
sudo nft list ruleset

Если iptables показывает:

(nf_tables)

команда, вероятно, работает через совместимый слой nftables.

Рекомендуется:


UFW

UFW (Uncomplicated Firewall) — упрощённый интерфейс для настройки firewall в Debian- и Ubuntu-подобных системах.

UFW скрывает детали iptables/nftables и позволяет описывать правила в более простом виде.

Проверить статус:

sudo ufw status

Подробный статус:

sudo ufw status verbose

Включить UFW:

sudo ufw enable

Отключить:

sudo ufw disable

Перед включением на удалённом сервере необходимо разрешить SSH.


Политики UFW

Запретить входящие соединения по умолчанию:

sudo ufw default deny incoming

Разрешить исходящие соединения:

sudo ufw default allow outgoing

Запретить маршрутизацию:

sudo ufw default deny routed

Для обычного веб-сервера типичный вариант:

sudo ufw default deny incoming
sudo ufw default allow outgoing

Разрешение портов в UFW

Разрешить SSH:

sudo ufw allow 22/tcp

Разрешить HTTP:

sudo ufw allow 80/tcp

Разрешить HTTPS:

sudo ufw allow 443/tcp

Разрешить оба веб-порта:

sudo ufw allow 80,443/tcp

Разрешить UDP-порт:

sudo ufw allow 51820/udp

Разрешение по имени профиля

UFW может использовать профили приложений:

sudo ufw app list

Пример:

Nginx Full
OpenSSH
Apache

Разрешить OpenSSH:

sudo ufw allow OpenSSH

Разрешить Nginx с HTTP и HTTPS:

sudo ufw allow "Nginx Full"

Список правил:

sudo ufw status numbered

Ограничение доступа по IP

Разрешить SSH только из подсети:

sudo ufw allow from 198.51.100.0/24 to any port 22 proto tcp

Разрешить HTTPS только конкретному адресу:

sudo ufw allow from 198.51.100.25 to any port 443 proto tcp

Запретить адрес:

sudo ufw deny from 203.0.113.50

Ограничить частоту SSH-подключений:

sudo ufw limit 22/tcp

Это может помочь против простых переборов, но не заменяет:


Удаление правила UFW

По номеру:

sudo ufw status numbered
sudo ufw delete 3

Повторить исходное правило:

sudo ufw delete allow 80/tcp

Логирование UFW

Включить обычное логирование:

sudo ufw logging on

Более подробные уровни:

sudo ufw logging low
sudo ufw logging medium
sudo ufw logging high

На серверах с большим количеством трафика чрезмерное логирование может создать много записей.


firewalld

firewalld — динамический менеджер firewall, распространённый в Fedora, RHEL, CentOS Stream, Rocky Linux и AlmaLinux.

В основе современных конфигураций firewalld может использовать nftables.

Основные понятия:


Зоны firewalld

Зона описывает уровень доверия к сетевому подключению.

Посмотреть активные зоны:

sudo firewall-cmd --get-active-zones

Получить список всех зон:

sudo firewall-cmd --get-zones

Посмотреть текущую зону по умолчанию:

sudo firewall-cmd --get-default-zone

Пример активной зоны:

public
  interfaces: eth0

Runtime и permanent

firewalld разделяет настройки на:

Добавить порт только временно:

sudo firewall-cmd --zone=public \
  --add-port=443/tcp

Добавить порт постоянно:

sudo firewall-cmd --zone=public \
  --permanent \
  --add-port=443/tcp

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

sudo firewall-cmd --reload

Если добавить правило только с --permanent, оно не всегда начинает действовать немедленно до перезагрузки или reload.


Разрешение сервисов

Список доступных сервисов:

sudo firewall-cmd --get-services

Разрешить SSH:

sudo firewall-cmd --zone=public \
  --permanent \
  --add-service=ssh

Разрешить HTTP:

sudo firewall-cmd --zone=public \
  --permanent \
  --add-service=http

Разрешить HTTPS:

sudo firewall-cmd --zone=public \
  --permanent \
  --add-service=https

Применить изменения:

sudo firewall-cmd --reload

Разрешение портов

sudo firewall-cmd --zone=public \
  --permanent \
  --add-port=8080/tcp

Разрешить диапазон:

sudo firewall-cmd --zone=public \
  --permanent \
  --add-port=6000-6010/tcp

Удалить порт:

sudo firewall-cmd --zone=public \
  --permanent \
  --remove-port=8080/tcp

Просмотр настроек

sudo firewall-cmd --zone=public --list-all

Все зоны:

sudo firewall-cmd --list-all-zones

Проверить, разрешён ли порт:

sudo firewall-cmd --zone=public \
  --query-port=443/tcp

Проверить, разрешён ли сервис:

sudo firewall-cmd --zone=public \
  --query-service=https

Ограничение по источнику

Создать правило для подсети с использованием rich rule:

sudo firewall-cmd --zone=public \
  --permanent \
  --add-rich-rule='rule family="ipv4" source address="198.51.100.0/24" port port="22" protocol="tcp" accept'

Применить:

sudo firewall-cmd --reload

Запретить адрес:

sudo firewall-cmd --zone=public \
  --permanent \
  --add-rich-rule='rule family="ipv4" source address="203.0.113.50" drop'

Цепочки правил

Цепочка — последовательность правил, через которую проходит пакет.

В разных инструментах терминология отличается, но логика похожа.

В iptables

Основные цепочки:

INPUT
OUTPUT
FORWARD

Дополнительные цепочки можно создавать самостоятельно.

В nftables

Цепочка привязывается к сетевому hook:

input
output
forward

Она может иметь политику:

accept
drop

В firewalld

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

В UFW

Пользователь задаёт простые правила, а UFW самостоятельно преобразует их в правила нижнего уровня.


Основные направления трафика

Входящий трафик

Соединение направлено к текущему серверу:

Клиент → веб-сервер

Обычно управляется цепочкой:

INPUT

Для веб-сервера разрешаются порты:

80/tcp
443/tcp

Исходящий трафик

Соединение инициируется самим сервером:

Веб-сервер → DNS-сервер
Веб-сервер → база данных
Веб-сервер → внешний API

Управляется цепочкой:

OUTPUT

Частая базовая политика:

INPUT  DROP
OUTPUT ACCEPT

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

Пересылаемый трафик

Пакет проходит через сервер:

Клиент → Linux-шлюз → другой сервер

Управляется цепочкой:

FORWARD

Это важно для:


Настройка firewall для веб-сервера

Предположим, сервер предоставляет:

Нужно разрешить:

TCP 22
TCP 80
TCP 443

Остальные входящие соединения следует запретить.


Подготовка

Перед изменением firewall нужно определить:

Проверить адреса:

ip addr

Проверить слушающие порты:

sudo ss -tulpen

Проверить текущий SSH-сеанс:

echo "$SSH_CONNECTION"

Не следует закрывать текущую SSH-сессию сразу после изменения правил. Сначала нужно открыть вторую сессию и проверить подключение.


Вариант с UFW

Установить политику по умолчанию:

sudo ufw default deny incoming
sudo ufw default allow outgoing

Разрешить SSH:

sudo ufw allow 22/tcp

Разрешить веб-трафик:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Включить firewall:

sudo ufw enable

Проверить:

sudo ufw status verbose

Ожидаемая логика:

Входящие: запрещены по умолчанию
SSH: разрешён
HTTP: разрешён
HTTPS: разрешён
Исходящие: разрешены

Если SSH работает на нестандартном порту, например 2222:

sudo ufw allow 2222/tcp

После проверки можно удалить правило для старого порта 22, если оно больше не нужно:

sudo ufw delete allow 22/tcp

Вариант с firewalld

Установить постоянную политику для зоны:

sudo firewall-cmd --zone=public \
  --permanent \
  --add-service=ssh

sudo firewall-cmd --zone=public \
  --permanent \
  --add-service=http

sudo firewall-cmd --zone=public \
  --permanent \
  --add-service=https

Применить:

sudo firewall-cmd --reload

Проверить:

sudo firewall-cmd --zone=public --list-all

Если SSH использует порт 2222:

sudo firewall-cmd --zone=public \
  --permanent \
  --add-port=2222/tcp

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

sudo firewall-cmd --zone=public \
  --permanent \
  --remove-service=ssh

Затем:

sudo firewall-cmd --reload

Вариант с nftables

Пример базовой конфигурации:

#!/usr/sbin/nft -f

flush ruleset

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

        # Локальные соединения
        iifname "lo" accept

        # Ответы на уже разрешённые соединения
        ct state established,related accept

        # Отбрасывать некорректные пакеты
        ct state invalid drop

        # Диагностический и служебный трафик
        meta l4proto icmp accept
        meta l4proto icmpv6 accept

        # SSH
        tcp dport 22 ct state new accept

        # HTTP и HTTPS
        tcp dport { 80, 443 } ct state new accept
    }

    chain forward {
        type filter hook forward priority 0;
        policy drop;
    }

    chain output {
        type filter hook output priority 0;
        policy accept;
    }
}

Проверить синтаксис:

sudo nft -c -f /etc/nftables.conf

Загрузить:

sudo nft -f /etc/nftables.conf

Проверить правила:

sudo nft list ruleset

Вариант с iptables

Пример порядка правил:

# Разрешить loopback
sudo iptables -A INPUT -i lo -j ACCEPT

# Разрешить уже установленные соединения
sudo iptables -A INPUT \
  -m conntrack \
  --ctstate ESTABLISHED,RELATED \
  -j ACCEPT

# Разрешить SSH
sudo iptables -A INPUT \
  -p tcp \
  --dport 22 \
  -m conntrack --ctstate NEW \
  -j ACCEPT

# Разрешить HTTP
sudo iptables -A INPUT \
  -p tcp \
  --dport 80 \
  -m conntrack --ctstate NEW \
  -j ACCEPT

# Разрешить HTTPS
sudo iptables -A INPUT \
  -p tcp \
  --dport 443 \
  -m conntrack --ctstate NEW \
  -j ACCEPT

# Политики
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

Проверить:

sudo iptables -L -n -v

Правила iptables могут исчезнуть после перезагрузки, если не настроить сохранение.

В Debian/Ubuntu часто используют пакет:

iptables-persistent

Сохранение правил:

sudo netfilter-persistent save

В других системах способ сохранения может отличаться.


Безопасная последовательность настройки

На удалённом сервере рекомендуется соблюдать порядок:

  1. Открыть дополнительную SSH-сессию.
  2. Узнать текущий SSH-порт.
  3. Разрешить SSH в firewall.
  4. Разрешить необходимые веб-порты.
  5. Проверить конфигурацию.
  6. Открыть ещё одну SSH-сессию.
  7. Проверить доступность HTTP и HTTPS.
  8. Только после этого включить строгую политику.
  9. Сохранить конфигурацию.
  10. Проверить правила после перезагрузки или reload.

Не следует начинать с команды:

sudo iptables -P INPUT DROP

если правило для SSH ещё не добавлено.


Проверка доступности портов

На сервере:

sudo ss -lntup