Tutorial

Настройка Packet Filter (PF) в FreeBSD 12.1

Published on April 29, 2020
Русский
Настройка Packet Filter (PF) в FreeBSD 12.1

Автор выбрал COVID-19 Relief Fund для получения пожертвования в рамках программы Write for DOnations.

Введение

Брандмауэр, вероятно, является одной из наиболее важных линий защиты от кибератак. Способность настроить брандмауэр с нуля — это очень важный навык, который позволяет администратору получить контроль над своими сетями.

Packet Filter (PF) — это известный брандмауэр, поддерживаемый в рамках проекта OpenBSD для обеспечения безопасности. Если быть более точным, это инструмент фильтрации пакетов, как видно из названия, который известен простым синтаксисом, удобством для пользователей и обширным функционалом. PF — это по умолчанию хранящий состояние брандмауэр, помещающий информацию о подключениях в таблице состояния, которую можно использовать в аналитических целях. PF — это часть базовой системы FreeBSD, которая поддерживается активным сообществом разработчиков. Хотя между версиями PF во FreeBSD и OpenBSD существуют различия, связанные с разной архитектурой ядра, в целом они используют один синтаксис. В зависимости от сложности общий набор правил можно изменить, чтобы работать с любым дистрибутивом с минимальными усилиями.

В этом обучающем руководстве мы выполним сборку брандмауэра с нуля на сервере FreeBSD 12.1 с помощью PF. Вы создадите базовый набор правил, который можно использовать в качестве шаблона для будущих проектов. Также вы познакомитесь с рядом продвинутых функций PF, таких как гигиена пакетов, предотвращение атак brute force, мониторинг и логирование, а также рядом сторонних инструментов.

Предварительные требования

Перед началом выполнения этого обучающего руководства вам потребуется следующее:

  • Сервер FreeBSD 12.1 с 1 ГБ памяти (ZFS или UFS). Вы можете воспользоваться нашим руководством по началу работы с FreeBSD для настройки вашего сервера согласно предпочитаемой конфигурации.
  • FreeBSD не имеет активированного по умолчанию брандмауэра, кастомизация — это один из важнейших принципов FreeBSD. Таким образом, при первом запуске вашего сервера вам потребуется временная защита, пока будет выполняться настройка PF. Если вы используете DigitalOcean, вы можете активировать облачный брандмауэр сразу после запуска сервера. Инструкции по настройке облачного брандмауэра см. в кратком руководстве по брандмауэру DigitalOcean. Если вы используете услуги другого поставщика облачных решений, воспользуйтесь самым быстрым способом для немедленной защиты перед началом работы. Какой бы метод вы ни выбрали, ваш временный брандмауэр должен разрешать только входящий трафик SSH и может разрешать любой исходящий трафик.

Шаг 1 — Создание предварительного набора правил

Начните выполнение данного руководства, создав черновик предварительного набора правил, который обеспечивает базовую защиту и доступ к важнейшим услугам через Интернет. В настоящий момент у вас есть работающий сервер FreeBSD 12.1 с активным облачным брандмауэром.

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

Набор правил PF записывается в файл конфигурации /etc/pf.conf, который также является местом его расположения по умолчанию. Вы можете хранить этот файл в другом месте, если это указано в файле конфигурации /etc/rc.conf. В этом руководстве вы будете использовать местоположение по умолчанию.

Войдите на сервер с пользователем non-root user:

  1. ssh freebsd@your_server_ip

Далее создайте ваш файл /etc/pf.conf:

  1. sudo vi /etc/pf.conf

Примечание. Если вы захотите посмотреть полный базовый набор правил в любой момент при выполнении руководства, см. примеры в шаге 4 и шаге 8.

PF фильтрует пакеты в соответствии с тремя основными действиями: block, pass и match. В сочетании с другими опциями они образуют правила. Действие выполняется, когда пакет соответствует критериям, указанным в правиле. Как вы можете ожидать, правила pass и block будут пропускать и блокировать трафик. Правило match выполняет действие с пакетом при обнаружении соответствующих критериев, но не пропускает или блокирует его. Например, оно может выполнять преобразование сетевых адресов (NAT) для соответствующего пакета, не блокируя или пропуская его, пакет останется на месте, пока вы не скажете ему сделать что-то в другом правиле, например, направите его на другой сервер или шлюз.

Далее добавьте первое правило в ваш файл /etc/pf.conf:

/etc/pf.conf
block all

Это правило блокирует все формы трафика в каждом направлении. Поскольку направление на указано, по умолчанию блокируется входящий и исходящий трафик. Данное правило является законным для локальных рабочих станций, которые необходимо изолировать от мира, однако оно во многом не пригодно к использованию на практике и не будет работать на удаленном сервере, поскольку оно запрещает трафик SSH. На деле, если бы вы активировали PF, то могли бы заблокировать для себя доступ к серверу.

Измените ваш файл /etc/pf.conf, чтобы разрешить трафик SSH в следующих выделенных строках:

/etc/pf.conf
block all
pass in proto tcp to port 22

Примечание. В качестве альтернативы вы можете использовать имя протокола:

/etc/pf.conf
block all
pass in proto tcp to port ssh

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

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

Теперь вы можете подключиться к серверу через SSH, но вы все равно можете блокировать все формы исходящего трафика. Это проблема, поскольку вы не можете получить доступ к критическим сервисам из Интернета для установки пакетов, обновления настроек времени и т. д.

Для устранения этой проблемы добавьте следующее выделенное правило в конце файла /etc/pf.conf:

/etc/pf.conf
block all
pass in proto tcp to port { 22 }
pass out proto { tcp udp } to port { 22 53 80 123 443 }

Теперь ваш набор правил разрешает исходящий трафик SSH, DNS, HTTP, NTP и HTTPS, а также блокирует весь входящий трафик (за исключением SSH). Вы размещаете номера портов и протоколы в фигурные скобки, которые образуют список в синтаксисе PF, что позволяет добавлять дополнительные номера портов, если это потребуется. Также вы добавляете разрешающее правило для протокола UDP на портах 53 и 123, поскольку DNS и NTP часто переключаются между протоколами TCP и UDP. Вы почти закончили работу с предварительным набором правил, осталось только добавить несколько правил для получения базового функционала.

Добавьте в предварительный набор правил следующие выделенные правила:

Preliminary Ruleset /etc/pf.conf
set skip on lo0
block all
pass in proto tcp to port { 22 }
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass out inet proto icmp icmp-type { echoreq }

Сохраните и закройте файл.

Вы создали правило set skip для устройства закольцовывания, поскольку ему не требуется фильтр трафика, а такая фильтрация может вызывать заметное замедление работы сервера. Вы добавили правило pass out inet​​​ для протокола ICMP, которое позволяет использовать утилиту ping(8) для поиска и устранения проблем. Опция inet представляет семейство адресов IPv4.

ICMP — это многоцелевой протокол обмена сообщениями, используемый сетевыми устройствами для различных видов коммуникации. Например, утилита ping использует сообщения, известные как echo request, которые вы добавили в список icmp_type. В качестве меры предосторожности вы разрешаете только типы сообщений, которые вам нужны для предотвращения контакта нежелательных устройств с вашим сервером. По мере роста ваших потребностей вы можете добавить в список новые типы сообщений.

Теперь у вас есть рабочий набор правил, который обеспечивает базовый функционал для большинства серверов. В следующем разделе мы убедимся, что все работает корректно, активировав PF и протестировав ваш предварительный набор правил.

Шаг 2 — Тестирование вашего предварительного набора правил

На этом шаге мы протестируем ваш предварительный набор правил и выполним переход с облачного брандмауэра на ваш брандмауэр PF, позволив PF взять полный контроль над ситуацией. Вы активируете ваш набор правил с помощью утилиты pfctl, которая представляет собой встроенный инструмент командной строки PF и основной метод взаимодействия с PF.

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

FreeBSD использует сеть shell-скриптов, известную как система rc, чтобы управлять запуском служб во время загрузки, а мы укажем эти службы в разных файлах конфигурации rc. Для таких глобальных служб, как PF, вы будете использовать файл /etc/rc.conf. Поскольку файлы rc имеют критическое значение для нормальной работы системы FreeBSD, они не должны редактироваться напрямую. Вместо этого FreeBSD предоставляет утилиту командной строки sysrc, которая предназначена для безопасного редактирования этих файлов.

Давайте активируем PF, используя утилиту командной строки sysrc:

  1. sudo sysrc pf_enable="YES"
  2. sudo sysrc pflog_enable="YES"

Проверьте внесение изменений, отобразив содержимое вашего файла /etc/rc.conf:

  1. sudo cat /etc/rc.conf

Результат будет выглядеть следующим образом:

Output
pf_enable="YES" pflog_enable="YES"

Также вы активируете службу pflog, которая, в свою очередь, активирует демон pflogd для ведения журнала PF. Вы поработаете с журналами позже.

Вы должны указать две глобальные службы в вашем файле /etc/rc.conf, но они не инициализируются, пока вы не перезагрузите сервер или не запустите их вручную. Перезапустите сервер, чтобы протестировать ваш доступ через SSH.

Запустите PF, перезапустив сервер:

  1. sudo reboot

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

Теперь снова подключитесь по SSH к серверу:

  1. ssh freebsd@your_server_ip

Хотя ваши службы PF уже проинициализированы, вы еще не загрузили ваш набор правил /etc/pf.conf, что означает, что ваш брандмауэр еще не активен.

Загрузите набор правил с помощью pfctl:

  1. sudo pfctl -f /etc/pf.conf

Если ошибки или сообщения отсутствуют, это означает, что ваш набор правил не имеет ошибок, а брандмауэр активен.

Теперь, когда PF запущен, вы можете отключить ваш сервер от облачного брандмауэра. Это можно сделать в панели управления вашей учетной записи DigitalOcean, удалив дроплет из портала облачного брандмауэра. Если вы используете другого поставщика облачных услуг, убедитесь, что все, что вы использовали для временной защиты, отключено. Запуск двух разных брандмауэров на сервере практически точно вызовет проблемы.

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

  1. sudo reboot

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

  1. ssh freebsd@your_server_ip

Теперь PF — ваш действующий брандмауэр. Чтобы проверить, что он запущен, вы можете попробовать получить доступ к данным с помощью утилиты pfctl.

Давайте рассмотрим некоторые статистические данные и счетчики с помощью pfctl -si​​​:

  1. sudo pfctl -si

Вы передаете флаги -si, которые означают show info, т. е. показать информацию. Это одна из многочисленных комбинаций параметров фильтра, которую вы можете использовать с pfctl для парсинга данных об активности брандмауэра.

Вы увидите следующие данные в таблице (значения будут варьироваться в зависимости от сервера):

Output
Status: Enabled for 0 days 00:01:53 Debug: Urgent State Table Total Rate current entries 5 searches 144 1.3/s inserts 11 0.1/s removals 6 0.1/s Counters match 23 0.2/s bad-offset 0 0.0/s fragment 0 0.0/s short 0 0.0/s normalize 0 0.0/s memory 0 0.0/s bad-timestamp 0 0.0/s congestion 0 0.0/s ip-option 0 0.0/s proto-cksum 0 0.0/s state-insert 0 0.0/s state-limit 0 0.0/s src-limit 0 0.0/s synproxy 0 0.0/s map-failed 0 0.0/s

Поскольку вы только что активировали набор правил, вы не увидите большое количество информации. Однако этот вывод показывает, что PF уже записал 23 совпавших правила. Это означает, что критерии набора правил были использованы 23 раза. Вывод также подтверждает, что ваш брандмауэр работает.

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

Давайте проверим подключение через Интернет и службу DNS с помощью ping для google.com:

  1. ping -c 3 google.com

Поскольку вы использовали флаг -c 3 при запуске, вы увидите три успешные попытки подключения:

Output
PING google.com (172.217.0.46): 56 data bytes 64 bytes from 172.217.0.46: icmp_seq=0 ttl=56 time=2.088 ms 64 bytes from 172.217.0.46: icmp_seq=1 ttl=56 time=1.469 ms 64 bytes from 172.217.0.46: icmp_seq=2 ttl=56 time=1.466 ms --- google.com ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 1.466/1.674/2.088/0.293 ms

Убедитесь, что у вас есть доступ к репозиторию pkgs с помощью следующей команды:

  1. sudo pkg upgrade

Если имеются какие-либо обновления для пакетов, выполните обновление.

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

Шаг 3 — Дополнение базового набора правил

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

Включение макросов и таблиц

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

Откройте ваш файл, чтобы передать некоторые параметры в макрос:

  1. sudo vi /etc/pf.conf

Теперь добавьте в самый верх набора правил следующее содержание:

/etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq }"
. . .

Измените ваши предыдущие правила SSH и ICMP, указав новые переменные:

/etc/pf.conf
. . .
pass in on $vtnet0 proto tcp to port { 22 }
. . .
pass inet proto icmp icmp-type $icmp_types
. . .

Ваши предыдущие правила SSH и ICMP теперь используют макросы. Имена переменных отображаются с помощью принятого в PF синтаксиса со знаком доллара. Вы назначаете интерфейс vtnet0 для переменной с тем же именем только в качестве формальности, что позволяет переименовать ее в будущем, если возникнет такая потребность. Другие распространенные имена переменных для общедоступных интерфейсов включают $pub_if​​​ или $ext_if.

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

Создайте эту таблицу, добавив следующее содержание сразу после макроса icmp_types:

/etc/pf.conf
. . .
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }
. . .

Теперь добавьте ваши правила для таблицы <rfc6890> под правилом set skip on lo0:

/etc/pf.conf
. . .
set skip on lo0
block in quick on egress from <rfc6890>
block return out quick on egress to <rfc6890>
. . .

Здесь вы добавляете опцию return, которая дополняет ваше правило block out​​​. Эта команда отклоняет пакеты и отправляет сообщение RST на хост, который попытался установить эти подключения, что полезно для анализа активности хоста. Затем добавьте ключевое слово egress, которое автоматически находит маршруты по умолчанию для любых заданных интерфейсов. Обычно это более простой метод поиска маршрутов по умолчанию, особенно для сложных сетей. Ключевое слово quick выполняет правила немедленно без учета остальной части набора правил. Например, если пакет с нелогичными IP-адресами попытается подключиться к серверу, вы можете захотеть немедленно сбросить соединение, и у вас не будет причин пропускать этот пакет через остальную часть набора правил.

Защита портов SSH

Поскольку ваш порт SSH общедоступен, он может стать объектом атаки. Один из самых очевидных признаков нападения — это массовые попытки входа в систему. Например, если один IP-адрес пытается выполнить вход на ваш сервер 10 раз за секунду, вы можете предположить, что это дело рук не человека, а компьютерного программного обеспечения, которое пытается взломать ваш пароль входа в систему. Такие виды систематических эксплойтов часто называют атаками brute force​​​, и обычно они являются успешными, если у сервера слабый пароль.

Предупреждение. Мы настоятельно рекомендуем использовать аутентификацию по открытому ключу на всех ваших серверах. Ознакомьтесь с руководством DigitalOcean по аутентификации на базе ключей.

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

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

/etc/pf.conf
. . .
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
. . .

Вы добавили опцию keep state, которая позволяет определить критерии состояния для таблицы устранения перегрузки: Вы передаете параметр max-src-conn, чтобы указать разрешенное количество одновременных подключений с одного хоста в секунду, а также параметр max-src-conn-rate, чтобы указать разрешенное количество новых подключений с одного хоста в секунду. Вы указали 15 подключений для max-src-conn и 3 подключения для max-src-conn-rate. Если хост превышает эти ограничения, механизм устранения перегрузки добавляет IP-адрес источника в таблицу <bruteforce>, которая запрещает его использование на сервере. Наконец, опция flush global немедленно сбрасывает подключение.

Вы определили таблицу устранения перегрузки в вашем правиле SSH, но не объявили саму таблицу в вашем наборе правил.

Добавьте таблицу <bruteforce> под макросом icmp_types:

/etc/pf.conf
. . .
icmp_types = "{ echoreq }"
table <bruteforce> persist
. . .

Ключевое слово persist позволяет создавать пустую таблицу в наборе правил. Без него PF будет жаловаться, что в таблице нет IP-адресов.

Эти меры гарантируют защиту вашего порта SSH с помощью мощного механизма безопасности. PF позволяет настраивать быстрые решения для защиты от катастрофических форм атак. В следующих разделах мы выполним действия для очистки пакетов, которые поступают на сервер.

Очистка вашего трафика

Примечание. В следующих разделах описываются базовые принципы работы протокола TCP/IP. Если вы планируете создавать веб-приложения или работать с сетью, вам будет полезно знать эти вещи. Ознакомьтесь с руководством DigitalOcean Знакомство с сетевой терминологией, интерфейсами и протоколами.

Из-за сложности протокола TCP/IP, а также действий злоумышленников пакеты часто поступают с отклонениями и неопределенностями, например с наложением фрагментов IP-адресов, поддельными IP-адресами и многим другим. Поэтому необходимо очищать трафик, прежде чем он поступит в систему. Технический термин, используемый для обозначения этого процесса, — нормализация.

Когда данные передаются через Интернет, они обычно разбиваются на небольшие фрагменты в источнике, чтобы отвечать параметрам передачи целевого хоста, где эти фрагменты пересобираются в полные пакеты. К сожалению, злоумышленники могут взламывать этот процесс большим количеством способов, описание которых выходит за пределы данного руководства. Кроме того, с PF вы можете управлять фрагментацией с помощью одного правила. PF имеет ключевое слово scrub, с помощью которого производится нормализация пакетов.

Добавьте ключевое слово scrub непосредственно перед правилом block all​​​:

/etc/pf.conf
. . .
set skip on lo0
scrub in all fragment reassemble max-mss 1440
block all
. . .

Это правило применяется для очищения входящего трафика. Вы добавили опцию fragment reassemble, которая предотвращает попадание фрагментов в систему. Вместо этого они кэшируются в памяти, пока не будут пересобраны в полные пакеты, что означает, что правилам фильтра придется работать только с единообразными пакетами. Также вы должны включить опцию max-mss 1440, которая представляет максимальный размер сегмента пересобираемых пакетов TCP, также известный как полезная нагрузка. Вы указываете значение 1440 байт, которое отражает баланс между размером и производительностью, оставляя достаточное пространство для заголовков.

Еще один важный аспект фрагментации — это термин, известный как максимальный передаваемый модуль данных (MTU). Протоколы TCP/IP позволяют устройствам обсуждать размеры пакетов для установления подключений. Целевой хост использует сообщения ICMP для информирования IP-адреса источника о своем MTU. Данный процесс известен как открытие пути MTU. Конкретный тип сообщения ICMP — destination unreachable. Вы должны активировать открытие пути MTU, добавив тип сообщения unreach в ваш список icmp_types.

Вы будете использовать стандартное значение MTU в 1500 байт, которое можно определить с помощью команды ifconfig:

  1. ifconfig

Вы увидите следующий вывод, который включает ваше текущее значение MTU:

Output
vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=6c07bb<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,TSO4,TSO6,LRO,VLAN_HWTSO,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6> . . .

Обновите список icmp_types, чтобы добавить тип сообщения destination unreachable​​​:

/etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach}"
. . .

Теперь, когда у вас есть политики для обработки фрагментации, пакеты, которые попадают в вашу систему, будут единообразными и согласованными. Это желательно, поскольку огромное количество устройств обмениваются данными через Интернет.

Теперь вы можете заняться предотвращением другой опасности, известной как подмена IP (спуфинг). Злоумышленники часто изменяют IP-адрес источника, чтобы могло показаться, что он находится на доверенном узле внутри организации. PF включает директиву antispoofing для обработки подмененных IP-адресов источника. При применении для конкретного интерфейса (интерфейсов) эта директива блокирует весь трафик из сети данного интерфейса (если его источником не является сам интерфейс). Например, если вы примените директиву antispoofing для интерфейса (интерфейсов) с адресом 5.5.5.1/24, весь трафик из сети 5.5.5.0/24 не будет приниматься системой, если только его источником не является этот интерфейс (интерфейсы).

Добавьте следующее выделенное содержание, чтобы применить antispoofing для интерфейса vtnet0:

/etc/pf.conf
. . .
set skip on lo0
scrub in
antispoof quick for $vtnet0
block all
. . .

Сохраните и закройте файл.

Это правило для борьбы с подменой указывает, что весь трафик из сети (сетей) vtnet0 может передаваться только через интерфейс vtnet0, либо он будет немедленно отклонен с помощью ключевого слова quick. Злоумышленники не смогут скрыться в сети vtnet0 и взаимодействовать с другими узлами.

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

Выведите на экран содержимое /etc/pf.conf, используя pfctl со следующей командой:

  1. sudo pfctl -nvf /etc/pf.conf

Эта команда pfctl получает флаги -nvf, выводит набор правил и тестирует его без фактической загрузки данных, что известно как пробный прогон. Теперь вы увидите полное содержимое /etc/pf.conf в подробной форме.

Вы увидите примерно следующий вывод внутри части для борьбы с подменой IP-адресов:

Output
. . . block drop in quick on ! vtnet0 inet from your_server_ip/20 to any block drop in quick on ! vtnet0 inet from network_address/16 to any block drop in quick inet from your_server_ip to any block drop in quick inet from network_address to any block drop in quick on vtnet0 inet6 from your_IPv6_address to any . . .

Ваше правило показало, что это часть сети your_server_ip/20. Также оно обнаружило, что (в примере для данного обучающего руководства) сервер является частью сети network_address/16 и имеет дополнительный IPv6-адрес. Правило блокирует коммуникации системы со всеми этими сетями, если их трафик не проходит через интерфейс vtnet0.

Ваше правило для борьбы с подменой IP-адреса является последним добавлением в базовый набор правил. На следующем шаге вы примените эти изменения и выполните ряд тестов.

Шаг 4 — Тестирование базового набора правил

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

Вот как выглядит ваш полный базовый набор правил:

Base Ruleset /etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }

set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types

Убедитесь, что ваш файл /etc/pf.conf идентичен полному базовому набор правил, прежде чем продолжить. Сохраните и закройте файл.

Ваш полный базовый набор правил предоставляет вам следующее:

  • Набор макросов, который может определять ключевые службы и устройства.
  • Политика гигиены сети для решения проблем с фрагментацией пакетов и нелогичными IP-адресами.
  • Структура фильтрации default deny​​​, которая блокирует весь трафик и разрешает только то, что вы указываете.
  • Входящий доступ через SSH с ограничением количества одновременных подключений с одного хоста.
  • Политики для исходящего трафика, которые позволяют получить доступ к критически важным сервисам в Интернете.
  • Политики ICMP, которые обеспечивают доступ к утилите ping и открытию пути MTU.

Запустите следующую команду pfctl для выполнения пробного прогона:

  1. sudo pfctl -nf /etc/pf.conf

Вы передаете флаги -nf, которые указывают pfctl запускать набор правил без загрузки, в результате чего будут брошены ошибки, если что-то пойдет не так.

Теперь, если ошибки отсутствуют, загрузите набор правил:

  1. sudo pfctl -f /etc/pf.conf

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

Первый тест — подключение к Интернету и службе DNS:

  1. ping -c 3 google.com

Результат будет выглядеть следующим образом:

Output
PING google.com (172.217.0.46): 56 data bytes 64 bytes from 172.217.0.46: icmp_seq=0 ttl=56 time=2.088 ms 64 bytes from 172.217.0.46: icmp_seq=1 ttl=56 time=1.469 ms 64 bytes from 172.217.0.46: icmp_seq=2 ttl=56 time=1.466 ms --- google.com ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 1.466/1.674/2.088/0.293 ms

Затем проверьте, что вы можете получить доступ к репозиторию pkgs:

  1. sudo pkg upgrade

Еще раз обновите пакеты, если это необходимо.

В заключение перезапустите ваш сервер:

  1. sudo reboot

Подождите несколько минут, пока сервер не перезагрузится. Вы выполнили и имплементировали базовый набор правил, что является важным шагом с точки зрения вашего прогресса. Теперь вы готовы к изучению некоторых продвинутых функций PF. На следующем шаге вы сможете продолжить работу по предотвращению атак brute force.

Шаг 5 — Управление таблицей устранения перегрузки

Со временем таблица устранения перегрузки <bruteforce> будет заполнена IP-адресами злоумышленников, и вам придется выполнять ее периодическую очистку. Маловероятно, что злоумышленник будет использовать один и тот же IP-адрес, поэтому нет необходимости хранить эти адреса в таблице в течение длительного времени.

Вы можете использовать pfctl для ручной очистки IP-адресов, которые хранятся в таблице устранения перегрузки в течение 48 часов и более с помощью следующей команды:

  1. sudo pfctl -t bruteforce -T expire 172800

Вы увидите примерно следующий результат:

Output
0/0 addresses expired.

Вы передаете флаг -t bruteforce, что означает table bruteforce, и флаг -T, который позволяет запускать целый ряд встроенных команд. В этом случае вы должны запустить команду expire, чтобы очистить все записи из -t bruteforce со значением времени, указанным в секундах. Поскольку вы работаете на новом сервере, в таблице, вероятно, не будет IP-адресов.

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

Создайте файл скрипта оболочки в директории /usr/local/bin:

  1. sudo vi /usr/local/bin/clear_overload.sh

Добавьте в скрипт оболочки следующие строки:

/usr/local/bin/clear_overload.sh
#!/bin/sh

pfctl -t bruteforce -T expire 172800

Сделайте файл исполняемым с помощью следующей команды:

  1. sudo chmod 755 /usr/local/bin/clear_overload.sh

Далее вам необходимо создать задание cron. Это задания, которые будут запускаться периодически в соответствии с указанным вами временем. Часто они используются для резервного копирования или любого процесса, который необходимо запускать в одно и то же время каждый день. Создавать задания cron можно с помощью файлов crontab. Дополнительную информацию о cron(8) и crontab(5) см. в Man Pages.

Создайте файл crontab пользователя root с помощью следующей команды:

  1. sudo crontab -e

Теперь добавьте в файл crontab следующее содержимое:

crontab
# minute	hour	mday	month	wday	command

  *				0     *       *     *	  /usr/local/bin/clear_overload.sh

Сохраните и закройте файл.

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

Это задание cron запускает скрипт clear_overload.sh каждый день в полночь, удаляя IP-адреса, которые находятся в таблице перегрузки <bruteforce> более 48 часов. Далее вам необходимо добавить якоря в ваш набор правил.

Шаг 6 — Добавление якорей в ваши наборы правил

На этом шаге вы должны ввести якоря, которые используются для поиска правил в основном наборе правил, либо вручную, либо из внешнего текстового файла. Якоря могут содержать элементы правил, таблицы и даже другие якоря, которые называются вложенными якорями. Давайте продемонстрируем, как работают якоря, добавив таблицу во внешний файл, а затем выполним ее извлечение в ваш базовый набор правил. Ваша таблица будет включать группу внутренних хостов, для которой вы хотите ограничить подключение к внешнему миру.

Создайте файл под именем /etc/blocked-hosts-anchor:

  1. sudo vi /etc/blocked-hosts-anchor

Добавьте в файл следующие строчки:

/etc/blocked-hosts-anchor
table <blocked-hosts> { 192.168.47.1 192.168.47.2 192.168.47.3 }

block return out quick on egress from <blocked-hosts>

Сохраните и закройте файл.

Эти правила объявляются и определяются в таблице <blocked-hosts>​​​ и запрещают доступ с любого IP-адреса в таблице <blocked-hosts> к любым сервисам внешнего мира. Вы используете ключевое слово egress в качестве предпочитаемого метода поиска маршрута по умолчанию или выхода наружу, в Интернет.

Вам все еще необходимо объявить якорь в вашем файле /etc/pf.conf​​​:

  1. sudo vi /etc/pf.conf

Теперь добавьте следующие правила якоря после правила block all​​:

/etc/pf.conf
. . .
block all
anchor blocked_hosts
load anchor blocked_hosts from "/etc/blocked-hosts-anchor"
. . .

Сохраните и закройте файл.

Эти правила декларируют blocked_hosts и загружают правила якоря в ваш главный набор правил из файла /etc/blocked-hosts-anchor.

Теперь примените эти изменения, перезагрузив ваш набор правил с помощью pfctl:

  1. sudo pfctl -f /etc/pf.conf

Если ошибок нет, это означает, что в вашем наборе правил нет ошибок, а изменения активны.

Используйте pfctl для проверки запуска якоря:

  1. sudo pfctl -s Anchors

Флаг -s Anchors означает show anchors. Вывод должен выглядеть так:

Output
blocked_hosts

Утилита pfctl также может парсить конкретные правила вашего якоря с помощью флагов -a и -s:

  1. sudo pfctl -a blocked_hosts -s rules

Результат будет выглядеть следующим образом:

Output
block return out quick on egress from <blocked-hosts> to any

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

Давайте откроем /etc/pf.conf и добавим еще один якорь:

  1. sudo vi /etc/pf.conf

Вы можете назвать якорь rogue_hosts и поместить его в правило block all​​​:

/etc/pf.conf
. . .
block all
anchor rogue_hosts
. . .

Сохраните и закройте файл.

Чтобы применить изменения, перезагрузите набор правил с помощью pfctl:

  1. sudo pfctl -f /etc/pf.conf

Еще раз используйте pfctl для подтверждения запуска якоря:

  1. sudo pfctl -s Anchors

Результат будет выглядеть следующим образом:

Output
blocked_hosts rogue_hosts

Теперь, когда якорь запущен, вы можете добавить к нему правила в любое время. Проверьте это, добавив следующее правило:

  1. sudo sh -c 'echo "block return out quick on egress from 192.168.47.4" | pfctl -a rogue_hosts -f -'

Здесь вызывается команда echo и строковое содержимое, которое затем передается в утилиту pfctl с символом |, где оно обрабатывается в правило якоря. Откройте новый сеанс оболочки с помощью команды sh -c. Это связано с тем, что вы создаете связь между двумя процессами, но вам необходимо использовать права sudo для прохождения всей последовательности команд. Существует несколько способов решения этой проблемы, в нашем случае вы откроете дополнительный процесс оболочки с привилегиями sudo, используя для этого команду sudo sh -c.

Теперь воспользуйтесь pfctl еще раз, чтобы убедиться, что правила активны:

  1. sudo pfctl -a rogue_hosts -s rules

Результат будет выглядеть следующим образом:

Output
block return out quick on egress inet from 192.168.47.4 to any

Использование якорей является ситуационным и субъективным решением. Как и для любых других функций, существуют плюсы и минусы использования якорей. Некоторые приложения, такие как интерфейс blacklistd, изначально имеют якоря. Далее мы рассмотрим подробнее процесс записи журналов в PF, что является критически важным аспектом сетевой безопасности. Ваш брандмауэр будет бесполезен, если вы не можете посмотреть, что он делает.

Шаг 7 — Запись журнала активности вашего брандмауэра

На этом шаге мы будем работать с журналом PF, который управляется с помощью псевдоинтерфейса pflog. Функция ведения журнала активируется при загрузке с помощью добавления pflog_enabled=YES в файл /etc/rc.conf, что вы уже сделали на шаге 2. Это позволяет активировать демон pflogd, который генерирует интерфейс под именем pflog0 и записывает журналы в бинарном формате в файл /var/log/pflog. Журналы можно парсить в режиме реального времени из интерфейса или читать из файла /var/log/pflog с помощью утилиты tcpdump(8)​​.

Вначале получите доступ к журналам из файла /var/log/pflog:

  1. sudo tcpdump -ner /var/log/pflog

Вы передаете флаги -ner, которые форматируют вывод в удобочитаемый вид, а также указываете файл для чтения, в нашем случае это /var/log/pflog.

Результат будет выглядеть следующим образом:

Output
reading from file /var/log/pflog, link-type PFLOG (OpenBSD pflog file)

На этих ранних этапах в файле /var/log/pflog может не быть данных. В очень короткий срок файл журнала начнет расти в размере.

Также вы можете просмотреть журналы в реальном времени с помощью интерфейса pflog0, используя следующую команду:

  1. sudo tcpdump -nei pflog0

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

Результат будет выглядеть следующим образом:

Output
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 262144 bytes

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

Чтобы выйти из этого состояния и вернуться в командную строку, нажмите CTRL + Z.

В Интернете есть огромное количество информации о tcpdump(8), включая официальный сайт.

Доступ к файлам журнала с помощью pftop

Утилита pftop — это инструмент для быстрого просмотра активности брандмауэра в реальном времени. Ее имя отсылает к хорошо известной утилите Unix top.

Для ее использования вам необходимо установить пакет pftop:

  1. sudo pkg install pftop

Теперь запустите бинарный файл pftop:

  1. sudo pftop

В результате будет получен следующий вывод (ваши IP-адреса будут отличаться):

Output
PR DIR SRC DEST STATE AGE EXP PKTS BYTES tcp In 251.155.237.90:27537 157.225.173.58:22 ESTABLISHED:ESTABLISHED 00:12:35 23:59:55 1890 265K tcp In 222.186.42.15:25884 157.225.173.58:22 TIME_WAIT:TIME_WAIT 00:01:25 00:00:06 22 3801 udp Out 157.245.171.59:4699 67.203.62.5:53 MULTIPLE:SINGLE 00:00:14 00:00:16 2 227

Создание дополнительных интерфейсов журнала

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

Создайте дополнительный интерфейс журнала с именем pflog1:

  1. sudo vi /etc/hostname.pflog1

Добавьте в файл /etc/hostname.pflog1 следующие строки:

/etc/hostname.pflog1
up

Теперь активируйте устройство при загрузке в вашем файле /etc/rc.conf​​​:

  1. sudo sysrc pflog1_enable="YES"

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

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

Шаг 8 — Возврат к вашему базовому набору правил

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

Откройте базовый набор правил с помощью следующей команды:

  1. sudo vi /etc/pf.conf

Удалите текущий набор правил в вашем файле и замените его на следующий базовый набор правил:

/etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }

set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types

Сохраните и закройте файл.

Перезагрузите набор правил:

  1. sudo pfctl -f /etc/pf.conf

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

Также вам необходимо отключить созданный вами интерфейс pflog1. Поскольку вы не знаете, понадобится ли он вам еще, вы можете отключить pflog1 с помощью утилиты sysrc:

  1. sudo sysrc pflog1_enable="NO"

Теперь удалите файл /etc/hostname.pflog1 из директории /etc:

  1. sudo rm /etc/hostname.pflog1

Прежде чем выходить, перезагрузите сервер еще раз, чтобы гарантировать, что все изменения активны и сохраняются:

  1. sudo reboot

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

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

Simple Web Server Ruleset
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <webcrawlers> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }

set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
pass in on $vtnet0 proto tcp to port { 80 443 } \
    keep state (max-src-conn 45, max-src-conn-rate 9/1, \
        overload <webcrawlers> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types

В результате создается таблица с именем <webcrawlers>, которая имеет более гибкую политику в отношении перегрузки, чем ваш порт SSH, согласно значениям max-src-conn 45 и max-src-conn-rate. Это связано с тем, что не все перегрузки связаны с действиями злоумышленников. Они также могут быть связаны с активностью незлонамеренных сетевых ботов, поэтому вы можете избежать чрезмерных мер безопасности на портах 80 и 443. Если вы решите использовать набор правил для веб-сервера, вам необходимо добавить таблицу <webcrawlers> в /etc/pf.conf и периодически очищать IP-адреса в таблице. Подробнее см. в шаге 5.

Заключение

В этом обучающем руководстве вы настроили PF в FreeBSD 12.1. Теперь у вас есть базовый набор правил, который может служить в качестве отправной точки для всех ваших проектов FreeBSD. Дополнительную информацию о PF можно найти на странице pf.conf(5)​​​ в Man Pages.

Посетите нашу страницу FreeBSD, чтобы найти дополнительные обучающие руководства и ответы на частые вопросы.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel