Рубрика:
Безопасность /
Сетевая безопасность
|
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|
ТАТЬЯНА ИЛЬЧЕНКО
IPFilter с самого начала
Для чего нужен пакетный фильтр? Это еще один инструмент для построения межсетевых экранов или, как еще их называют, firewall (в переводе с англ. – «огненная стена»), с помощью фильтрации трафика по заданным условиям. Способ защиты критически важных сегментов в точках входа в публичные сети и трансляции IP-адресов из немаршрутизируемых частных сетей в реальные IP-адреса.
В статье мы поговорим о том, как быстро настроить и запустить межсетевой экран с функциями трансляции адресов с помощью IPFilter на сервере под управлением ОС FreeBSD. Почему IPFilter? Во-первых, гибок и не громоздок. Является пакетным фильтром с функцией контроля соединений. Для серверов под большой нагрузкой это может стать критичным фактором при выборе программного обеспечения. Правила пишутся вполне понятным и почти привычным языком (последнее, правда, чисто субъективное мнение автора) – логическое построение правил интуитивно понятно и хорошо воспринимается, что тоже немаловажно при их большом количестве. Присутствуют такие удобные функции, как создание групп правил и ведение нескольких лог-файлов (в зависимости от того, что хочется фиксировать и потом анализировать). Помимо этого присутствует кросс-платформенность Поддержка реализована на уровне ядра операционной системы, впрочем, как и у «традиционного» IPFW, существенных недостатков которого, кроме отсутствия некоторых возможностей IPFilter, автор статьи на своем опыте использования межсетевых экранов не берется назвать.
На момент написания статьи текущая версия IPFilter v.4.1. Однако несмотря на заявление разработчиков о том, что она полностью протестирована в среде FreeBSD 4.9-RELEASE, установить её с ходу не удалось поэтому мы рассмотрим предыдущий релиз v3.4.31 (336), включенный, к слову, в ядро FreeBSD 4.9-RELEASE.
Все примеры даны в среде FreeBSD 4.9-RELEASE для IPFilter этой версии, которая по умолчанию поддерживается ядром FreeBSD. Официальная страница IPFilter расположена по адресу: http://coombs.anu.edu.au/~avalon/ip-filter.html.
Итак, приступим к установке, конфигурированию и запуску. Начнем, пожалуй, с того, как это работает и что нам понадобится сделать до того, как мы задействуем IPFilter В качестве описания конфигурации пакетного фильтра используется обычный текстовый файл, каждая строка которого описывает правило фильтрации. Строки, начинающиеся со знака «#», воспринимаются как комментарии. Логическая структура правил IPFilter выглядит примерно следующим образом:
[Res] [aLOG] [aKEY] [fastroute] [pDST] [FLAGS][KW]
где:
- <ACT> – действие, которое будет предпринято при обнаружении пакета, подпадающего под описываемое правило (pass/block);
- [Res] – какой ответ отправить[5] запрашивающей стороне (для блокируемых пакетов);
- <pTYP> – тип пакета (in/out);
- [aLOG] – фиксировать ли в файле протокола описанные пакеты (log);
- [aKEY] – ключевое слово quick, означающее, что если анализируемый пакет подпадает под данное правило, то дальнейший просмотр правил прекращается;
- <nDEV> – устройство, физический интерфейс, на котором «искать» совпадение с правилом для пакетов;
- [fastroute] – ключевое слово, используемое для сокрытия присутствия firewall как узла сети (пакет будет переправлен без изменения в TTL дальше по маршруту);
- <tPROT> – протокол (ip/udp/tcp);
- <aSRC> – адрес-источник пакета;
- <aDST> – адрес-приемник пакета;
- [pDST] – порт, на который адресован пакет;
- [FLAGS] – управляющие флаги;
- [KW] – директивы (keywords).
В угловых скобках приведены обязательные параметры/опции, а в квадратных соответственно те, наличие которых определяется конкретными обстоятельствами и не является безоговорочно обязательным.
Вооружившись этим представлением, создадим файл конфигурации, описывающий довольно простой набор правил.
К примеру, нам требуется дать возможность удаленным пользователям «снаружи» работать с FTP/HTTP(S)-сервисами, а нашему почтовому серверу – обмениваться почтой с окружающим миром по SMTP. Кроме того, необходимо описать правила для нашего DNS-сервера. Внешний интерфейс fxp1 имеет адрес 213.27.10.хх и маску 255.255.255.255, внутренняя сеть ограничена адресным пространством 192.168.10.0 и маской 255.255.255.0, что соответствует описанию сети как 192.168.10.0/24.
Руководствоваться для начала будем принципом «что не разрешено, то запрещено»
pass out quick on lo0 proto ip from 127.0.0.0/8 to 127.0.0.0/8
pass in quick on lo0 proto ip from 127.0.0.0/8 to 127.0.0.0/8
# Блокируем все входящие IP-соединения на lo0 из сети 127.0.0.0/8[8]
block in quick on lo0 proto ip from any to 127.0.0.0/8
Если входящий/исходящий пакет подпадает под эти правила, мы прекращаем поиск соответствий. При этом фиксироваться в файле протокола прохождение таких пакетов через интерфейс lo0 не будет.
# Блокируем все входящие IP/TCP/UDP-соединения на внешнем интерфейсе
block in log on fxp1 proto ip from any to any
block in log on fxp1 proto tcp from any to any
block in log on fxp1 proto udp from any to any
Обратим внимание, что все пакеты (запрещенные нами входящие соединения) не будут отбрасываться сразу, а будут передаваться дальше на проверку (отсутствует ключевое слово quick). Если соответствующего разрешения не будет найдено, пакет будет блокирован в соответствии с этими правилами. А «incident will be reported», как говорится. Сразу за этими строчками мы начнем добавлять правила в зависимости от уже продуманной к этому моменту (хорошо бы даже четко описанной «на бумаге») политики нашей «огненной стены». Для экономии времени на обработке файла с правилами условимся прекращать дальнейшее расcмотрение правил при подпадании пакета под заданные условия. Заметим, что каждый сервис потребует как минимум два правила: для входящих и для исходящих пакетов на каждый используемый сервисом порт. Также, памятуя о специфике каждого сервиса, будем задавать управляющие флаги, не забывая обращаться к документации по протоколам и к IPFilter Based Firewalls HOWTO.
FTP
Предположим, у вас имеется FTP-сервер, к которому вы хотите открыть публичный доступ. Как известно, в работе по протоколу FTP используется два порта – для передачи команд и, собственно, для передачи данных. В нотации стека протоколов TCP/IP для протокола FTP используется протокол транспортного уровня TCP. Соответственно для этого сервиса правила будут выглядеть следующим образом:
pass out quick on fxp1 log proto tcp/udp from 213.27.10.xx/32 to any keep state
pass in quick on fxp1 log proto tcp from any to 213.27.10.xx/32 port = 21 flags S keep state
Директива flag означает, что фильтр будет отслеживать флаги в каждом пакете и, если нужно, сравнивать с заданными флагами в правилах IPFilter. В данном случае мы будем отслеживать пакеты с установленным SYN – этот флаг присутствует в пакетах при инициализации TCP-соединения.
Здесь же мы впервые используем управляющий флаг keep state. Остановимся на нем поподробнее. Сами по себе пакетные фильтры не умеют различать начало, середину или конец любой TCP/UDP/ICMP, а ориентируются по установленному в пришедшем пакете FIN-флагу. Администратору же в данном случае остается только надеяться на то, что такие пакеты не будут FIN-сканированием. В IPFilter применена методика keeping state для распознавания установленных сессий и отличия их от действий злоумышленников. Разработчики исходили из того, что раз любая TCP/IP-сессия проходит в три этапа: старт (установка соединения), соединение и разрыв соединения (все это может уместиться и в одном-единственном пакете) – при этом, в общем случае (исключая злонамеренные действия), должны иметь место именно все три стадии. Если старт сессии разрешен правилами фильтра, то понятно, что последующие пакеты этой сессии (subsequent-пакеты) и ее стоп-пакет тоже должны быть пропущены. Так же, как если запрещено начало сессии, то и последующие пакеты будут автоматически блокированы. Такой подход также позволяет избежать IP stack overflow – переполнения IP-стека. Более подробное описание можно найти в IPFilter Based Firewalls HOWTO, где помимо описания работы IPFilter даны общие рекомендации по построению межсетевого экрана.
Разобравшись с keep state, обратимся к следующему управляющему флагу keep frags и рассмотрим его назначение. Дело в том, что использование keep state почти решает проблему защиты от FIN-сканирования. А в задаче настройки фильтрации нет места «почти»-решениям. Флаг keep frags позволяет IPFilter отмечать и в дальнейшем отслеживать фрагментированные пакеты, пропуская только ожидаемые фрагменты и отфильтровывая подложные.
HTTP(S)
#http
pass in log quick on fxp1 proto tcp from any to 213.27.10.xx/32 port = 80 flags S keep state keep frags
Для данного сервиса нам потребуется описать только правило для входящих пакетов, ибо одно из последних правил будет выглядеть следующим образом:
pass out log quick on fxp1 from 213.27.10.xx/32 to any
Это позволяет не описывать правила для исходящих пакетов от нашего веб-сервера (подразумевается, что веб-сервер не будет самостоятельно инициировать TCP-соединения, а станет только отвечать на входящие запросы).
# https
pass out log quick on fxp1 proto tcp from 213.27.10.xx/32 to any port = 443 keep state keep frags
pass in log quick on fxp1 proto tcp from any to 213.27.10.xx/32 port = 443 keep state keep frags
Эти правила дадут возможность пользователям или приложениям использовать в работе протокол Secure HTTP.
Замечание. Следует помнить, что даже если все запросы на веб-ресурсы от пользователей в локальной сети принудительно перенаправляются на порт вашего proxy-сервера, для некоторых клиентских программ (в частности, использующих метод CONNECT) – таких как, например, binkd или ICQ – может понадобиться разрешение для адресов локальной сети на работу по соответствующим портам через интерфейс, который будет «охраняться» нашим межсетевым экраном, то есть в нашем случае – через интерфейс fxp1.
SMTP
pass out log quick on fxp1 proto tcp from 213.27.10.xx/32 to any port = 25 keep state keep frags
pass in log quick on fxp1 proto tcp from any to 213.27.10.xx/32 port = 25 keep state keep frags
DNS
pass in log quick on fxp1 proto udp from any to 213.27.10.xx/32 port = 53 keep frags
pass out log quick on fxp1 proto udp from 213.27.10.xx/32 to any port = 53 keep frags
pass in log quick on fxp1 proto tcp from any to 213.27.10.xx/32 port = 53 keep state keep frags
pass out log quick on fxp1 proto tcp from 213.27.10.xx/32 to any port = 53 keep state keep frags
Здесь нам понадобятся 4 правила, так как описываемый сервис использует в работе на транспортном уровне TCP и UDP, соответственно и правила фильтрации должны это учитывать.
Рассмотрим теперь случай, когда нам необходимо пропускать в оба направления трафик на компьютере в нашей локальной сети, не назначая ему реального адреса. Подобная ситуация может возникнуть, если в вашей сети есть, например, ПО систем «клиент-банк», установленное на машине одного из сотрудников. Часто такие системы не ориентированы на использование обычных proxy-серверов, и приходится администратору задействовать проброс соединений прямо на бухгалтерскую машину.
В этом случае придется использовать не только правила firewall, но и транслирование адресов в нотации NPAT– применение ipnat описано чуть дальше. Итак, вот как будут выглядеть правила фильтрации трафика для такой программы (предполагается, что 194.84.xx.xx – адрес сервера, куда надо подсоединяться клиентской программе, 192.168.10.48 – адрес машины, где эта клиентская программа установлена):
pass out log quick on fxp1 proto tcp from 192.168.10.48/32 to 194.84.xx.xx/32 port = 1352 keep state keep frags
pass in log quick on fxp1 proto tcp from 194.84.xx.xx/32 to 192.168.10.48/32 port = 1352 keep state keep frags
Завершим же описание правил следующим образом:
pass out log quick on fxp1 from 213.27.10.xx/32 to any
block out log quick on fxp1 from any to any
То есть, все пакеты, для которых не найдено ранее соответствующих правил, будут фильтроваться следующим образом: безоговорочно пропускать все исходящие с нашего реального адреса пакеты, остальные исходящие – также безоговорочно блокировать. Входящие пакеты блокированы у нас в начале описания правил, помните?
Замечание. Внимательно следите за тем, чтобы правила не повторялись, иначе при запуске фильтр сообщит об ошибке:
2:ioctl(add/insert rule): File exists |
Первая цифра – это номер строки, где возникла ошибка, далее следует ее краткое описание, поясняющее, что ошибка возникла при попытке добавить/вставить правило и заключается она в том, что такое правило уже существует и занесено в активный набор правил
После того как мы описали все правила и сохранили файл с ними, к примеру, с именем ipf.rules в /etc, позаботимся о том, чтобы наши пользователи, имеющие адреса из подсетей, зарезервированных под private networks – 192.168/16, 172.16/12, 10/8 (такие подсети еще называют non-routeable – немаршрутизируемые или «серые»), – могли получить доступ к ресурсам Интернета через наш «firewall-интерфейс». Воспользуемся для этого входящим в состав IPFilter модулем ipnat. Создадим там же в /etc файл ipnat.rules
Тут же, если вам необходимо в силу обстоятельств использовать перенаправление по портам из внутренней сети во внешнюю, нужно добавить примерно вот такие строки (не забывая про вышеописанный случай с ПО «клиент-банк»). То есть, наш файл ipnat.rules будет выглядеть примерно следующим образом:
map fxp1 192.168.10.0/16 -> 0/32
map fxp1 192.168.10.48/32 -> 213.27.10.xx/32
rdr fxp1 213.27.10.xx/32 port 1352 -> 192.168.10.48 port 1352
Строки, начинающиеся с ключевого слова map, описывают трансляцию адресов. Указываем интерфейс, IP-адрес, который нуждается в такой подмене, и маску для этого адреса, далее следуют адрес и маска, на которые будет заменена соответствующая часть пакетов, выходящих с нашего сервера. У нас подобных правил будет два: трансляция всех «серых» IP-адресов нашей сети в «фальшивый» адрес 0/32 и IP-адреса, для которого мы будем использовать проброс соединений, в реальный IP-адрес нашего межсетевого экрана. Строка со словом rdr описывает именно проброс соединений, о котором мы говорили выше, когда рассматривали ситуацию с ПО «клиент-банк», не умеющем использовать прокси-сервер.
После этого нам остается внести необходимые изменения в файл rc.conf
# отключаем NAT-демон, оставшийся от IPFW
natd_enable="NO"
# запуск IPFilter при старте системы
ipfilter_enable="YES"
# путь к команде ipf, если вам неизвестен whereis, ipf вам поможет
ipfilter_program="/sbin/ipf"
# полный путь к файлу с правилами фильтрации
ipfilter_rules="/etc/ipf.rules"
# запуск ipnat при старте системы
ipnat_enable="YES"
# путь к команде ipnat, опять же находится по whereis ipnat
ipnat_program="/sbin/ipnat"
# полный путь к файлу с правилами трансляции и редиректа
ipnat_rules="/etc/ipnat.rules"
# дополнительные параметры команды ipnat
ipnat_flags=""
# запуск ipmon при старте системы
ipmon_enable="YES"
# путь к команде ipmon, тут уже понятно, да?
ipmon_program="/sbin/ipmon"
# параметры команды ipmon
ipmon_flags=" -D /var/log/ipmon.log &"
Теперь проверим права на файлы ipf.rules и ipnat.rules – они должны быть выставлены в 644, владелец root.
-rw-r--r-- 1 root wheel 19430 30 янв 11:52 /etc/ipf.rules -rw-r--r-- 1 root wheel 339 22 янв 13:12 /etc/ipnat.rules |
На этом подготовительный этап закончен, и мы переходим непосредственно к запуску IPFilter.
В общем случае, от вас даже не потребуется ничего сложного, поскольку IPFilter в системе уже есть и надо только «включить» его, что мы сейчас и рассмотрим подробнее.
Вам потребуется добавить в конфигурационный файл ядра системы (как правило, он располагается в /usr/src/sys/i386/conf/) следующие опции
options IPFILTER # включаем поддержку ipf
options IPFILTER_LOG # логирование ipf
Кроме этого, надо увеличить количество псевдо-устройств bpf (Berkley Packet Filter), используемых для анализа и фильтрации пакетов. Выбор конкретного значения напрямую зависит от того, сколько у вас будет использоваться интерфейсов для фильтрации.
Замечание. Этот параметр в ядре ОС определяется не только количеством физических устройств, но и количеством процессов, которые будут обращаться к этим устройствам в процессе своей работы – tcpdump, nessus etc.
В нашем случае один сетевой интерфейс используется IPFilter и добавим еще три bpf-устройства на случай большой загруженности и если нам понадобятся в дальнейшем утилиты вроде tcpdump.
pseudo-device bpf 4
После сделанных изменений в конфигурации ядра пересобираем его (подробно о конфигурировании и компиляции ядра FreeBSD можно посмотреть тут: http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig.html).
Перезагрузимся (это потребуется из-за пересборки ядра системы, так как «на лету» заменить одно ядро другим нельзя) и теперь мы можем проверить функционирование нашего межсетевого фильтра. Для этого можно воспользоваться, например, широко извеcтной утилитой nmap (http://www.insecure.org/nmap) или любым сканером безопасности: X-Spider, Nessuss и прочие.
Еще один немаловажный момент: тестировать сканированием межсетевой экран рациональнее с другого компьютера (если вы экспериментируете с IP-адресом, доступным из внешнего мира, то и неплохо иметь возможность просканировать его снаружи) – поскольку полученный результат будет более точно отражать положение вещей. Да и в реальной жизни скорее всего проверять на прочность межсетевой экран будут снаружи. Однако не мешает проверить его и изнутри вашей сети, поскольку по статистике около 80% всех инцидентов в сфере информационной безопасности происходит по вине собственных сотрудников компании
Вот как выглядит, к примеру, результат команды nmap, направленной на наш «учебный» межсетевой экран с другого компьютера и из другой подсети:
# nmap -sT 213.27.10.xx
Starting nmap V. 3.10ALPHA9 ( www.insecure.org/nmap/ ) Interesting ports on myserver.ru: (The 1600 ports scanned but not shown below are in state: filtered) Port State Service 21/tcp open ftp 25/tcp open smtp 53/tcp open domain 80/tcp open http 443/tcp open https Nmap run completed -- 1 IP address (1 host up) scanned in 9.078 seconds |
Кроме вышеописанных возможностей, в пакет IPFilter входят различные дополнительные утилиты, позволяющие контролировать функционирование межсетевого экрана, такие как, например, ipfstat или ipmon. Последнюю, к слову сказать, мы использовали для ведения лога IPFilter. Различие между утилитами ipfstat и ipmon в том, что первая показывает общую статистику работы IPFilter, а вторая фиксирует каждый пакет, подпавший под такое из правил, для которого указана опция log. Если вы посмотрите в /var/log/, то увидите там довольно быстро растущий файл с именем ipmon.log – именно его мы описали в rc.conf, как файл протокола для ipmon.
Утилита ipmon, входящая в дистрибутив IPFilter, которую мы использовали для формирования файла протокола нашего пакетного фильтра, записывает всю информацию о его работе в файл /var/log/ipmon.log:
-rw------- 1 root wheel 2450688 19 мар 01:14 /var/log/ipmon.log |
Если при первом запуске ipmon не находит указанный в качестве параметра файл протокола, то он будет создан именно с такими правами, как указано выше.
При достаточно большой нагрузке (порядка 200-300 Мб трафика в сутки) файл протокола разрастается тоже немаленькими темпами, а дисковое пространство небезгранично. Поэтому надо предусмотреть и ротацию этого файла, то есть периодическое архивирование, его «обнуление» и перезапуск ipmon. Каждый системный администратор решает подобные задачи, исходя из собственного опыта, знаний и умений. Я расскажу о возможном решении с помощью утилиты logrotate.
Эта утилита стала уже стандартом де-факто для автоматической ротации файлов протоколов операционной системы и прикладного программного обеспечения. Странно, что по умолчанию ее не оказалось в поставке FreeBSD-4.9 RELEASE, но она есть в портах. Коротко расскажу про установку. Тут совсем просто (никаких коллизий возникнуть не должно, за исключением установки недостающих пакетов, но на то она и установка из портов, чтобы все сделать самостоятельно):
# cd /usr/ports/sysutils/logrotate
# make
# make install
После того как компиляция и установка завершены, стоит внимательно изучить руководство к утилите logrotate, поэтому:
# man logrotate
Внимательно изучив это руководство, легким движением руки создаем свой файл конфигурации logrotate:
# cd /usr/local/etc/logrotate.conf.sample
# cp logrotate.conf.sample logrotate.conf
Затем добавляем в только что созданный предыдущей операцией файл logrotate.conf следующие строки:
# начало описания, указываем путь, к файлу протокола
/var/log/ipmon.log {
daily # периодичность ротации – ежедневно
rotate 14 # количество хранимых фрагментов
missingok # отсутствие файла ipmon.log не является ошибкой
notifempty # не обрабатывать, если файл пустой
noolddir # держать все файлы в одном и том же каталоге
compress # сжимать «ротированные» фрагменты
postrotate # здесь мы описываем, что нужно сделать после ротации – перезапустить процесс ipmon
/sbin/killall –HUP ipmon
} # конец описания ротации файла протокола IPFilter
После того как мы отредактировали файл конфигурации logrotate.conf, вносим в /etc/crontab следующую строку:
0 1 * * * /usr/local/sbin/logrotate –s /var/lib/logrotate.status /usr/local/etc/logrotate.conf
Теперь ротация файла протокола IPFilter будет производиться 1 раз в сутки. Решение не единственное – архивирование, «обнуление» файла протокола и перезапуск в случае необходимости использующего его процесса можно реализовать несколькими способами, в частности с помощью syslogd или посредством создания собственного сценария на shell/PERL etc.
При первом запуске IPFilter в /dev/ появится наряду с прочими необходимыми устройство ipl, из которого ipmon&ipfstat и читают необходимые данные о жизнедеятельности пакетного фильтра. А при отключении межсетевого экрана в ядре и пересборки/установки последнего эти устройства будут удалены из /dev.
Обратимся же теперь к такому немаловажному вопросу, как манипулирование правилами фильтрации и транслирования. Ведь не станем мы каждый раз перезагружать сервер после изменения файлов ipf.rules и/или ipnat.rules – будем использовать соответствующие команды ipf и ipnat.
В IPFilter есть два типа наборов правил (ruleset) – активный и неактивный. По умолчанию все операции (загрузка/сброс правил) производятся над активным набором. Неактивный (манипулирование этим набором осуществляется с помощью параметра -I команды ipf) может быть полезен при отладке – его использование помогает протестировать новые правила без сброса активного набора правил и вмешательства таким образом в работу «боевого» межсетевого экрана. Переключение между двумя наборами active/inactive производится с помощью параметра командной строки -s. Таким образом, мы можем создать копию работоспособного набора правил, сохранив его с другим именем, и использовать его потом для тестирования и отладки изменений.
Чтобы загрузить правила IPFilter, воспользуемся такой командой:
# ipf -Fa -f /etc/ipf.rules
Эта команда сбросит текущий активный набор правил и загрузит в него правила, описанные в указанном файле ipf.rules. Для ipnat подобная команда будет выглядеть следующим образом:
# ipnat -CF -f /etc/ipnat.rules
Вообще говоря, параметры командной строки у ipf и ipnat во многом совпадают, но все же не мешает внимательно изучить соответствующие разделы man-страниц для получения более полной информации об этих командах.
Заключение
Хочется отметить, что здесь описаны только основы построения межсетевого экрана на базе IPFilter, достаточные для того, чтобы быстро развернуть его на сервере с минимальными затратами времени. Однако рассмотренными в данной статье возможности IPFilter не ограничиваются. За рамками нашего разговора остались создание групп правил, уровни ведения логов и многое другое. Все это можно найти в упоминавшемся уже несколько раз документе IPFilter Based Firewalls HOWTO, MAN-страницах и в различных сборниках FAQ, разбросанных на просторах Сети. А поскольку главный критерий теории – практика, экспериментируйте, господа!
При написании данной статьи использовались следующие документы:
- IPFilter Based Firewalls HOWTO – http://www.obfuscation.org/ipf
- FreeBSD firewall using IP Filter by Hoang Q. Tran
- IPFilter FAQ – http://www.phildev.net/ipf/index.html
- IPFilter Examples – http://coombs.anu.edu.au/~avalon/examples.html
- Test the firewall system – http://www.cert.org/security-improvement/practices/p060.html
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|