суббота, 25 апреля 2009 г.

Оптимизация и харденинг правил IPFilter

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

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

Возьмем с нее работающую конфигурацию и разберем по основным блокам с некоторыми пояснениями.

Прежде всего - основной принцип, которого стараюсь придерживаться лично я:

Блокируем все, разрешаем только то, что необходимо.

Сначала всегда ставим блок, отсекающий мусор, фрагменты, основные атаки:

# ---------------------
# Common blocking rules
# ---------------------

# Block all IP fragments
block in quick all with frag

# Block all short IP fragments
block in quick proto tcp all with short

# Block any IP packets with options set in them
block in quick all with ipopts

# Block nmap OS fingerprint attempts
block in log first quick proto tcp all flags FUP

Данные правила блокируют обломки пакетов, возникающие ниоткуда пакеты (вне сессий) с установленными опциями, и сканы NMAP, определяющие OS.

Замечание: Для полного сбивания NMAP с толку последнего правила недостаточно, определению ОС весьма способствуют двунаправленные порты, для избежания которых, как будет видно далее, нужно просто вдумчиво написать конфигурацию IPF.

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

# Make sure the loopback allows packets to traverse it
# ---------- lo0 interface ---------
pass in quick on lo0 all
pass out quick on lo0 all
# ---------- lo0 interface ---------

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

# DEBUG ICMP permit rules
# --------- bge0 interface ----------
#pass in quick on bge0 proto icmp from any to host_name icmp-type echo keep state
#pass out quick on bge0 proto icmp from host_name to any icmp-type echorep keep state
# --------- bge0 interface ----------
# --------- bge1 interface ----------
#pass in quick on bge1 proto icmp from any to host_name2 icmp-type echo keep state
#pass out quick on bge1 proto icmp from host_name2 to any icmp-type echorep keep state
# --------- bge1 interface ----------
# --------- nge0 interface ----------
#pass in quick on nge0 proto icmp from any to host_name3 icmp-type echo keep state
#pass out quick on nge0 proto icmp from host_name3 to any icmp-type echorep keep state
# --------- nge0 interface ----------

# Group 300 - Opened incoming ports on bge1
# Group 300 setup
pass in on bge1 head 300
# --------- bge1 interface ----------
# 80 port - HTTP
pass in quick on bge1 proto tcp from any to host_name2 port=80 flags S keep state group 300
# 443 port - HTTPS
pass in quick on bge1 proto tcp from any to host_name2 port=443 flags S keep state group 300
# --------- bge1 interface ----------

# Group 400 - Opened incoming ports on nge0
# Group 400 setup
pass in on nge0 head 400
# -------- nge0 interface -----------
# 80 port - HTTP
pass in quick on nge0 proto tcp from any to host_name3 port=80 flags S keep state group 400
# 443 port - HTTPS
pass in quick on nge0 proto tcp from any to host_name3 port=443 flags S keep state group 400
# -------- nge0 interface -----------

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

Кстати, порты ICMP, открытые постоянно - это как раз то самое, что позволяет NMAP определить ОС (одним из способов), следовательно, оставим их закрытыми.

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

# Stealth for traceroute (hide as hop)
# ---------- bge0 interface ----------
#block in quick on bge0 fastroute proto udp from any to any port 33434 >< 33465
# ---------- bge0 interface ----------

Я называю его "тачка - невидимка". Машина становится "невидимой" для traceroute, добавляется данное правило на все порты, на которые могут приходить пакеты. Понятное дело, что сделать сервер совершенно необнаружимым это правило не может, но от тыканья traceroutом очень даже предохранит.

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

# Group 100 - Blocked networks on any interface
# Group 100 setup
block in all head 100
# Anti-spoofing rules
block in quick from 192.168.0.0/16 to any group 100
block in quick from 172.16.0.0/12 to any group 100
block in quick from 10.0.0.0/8 to any group 100
block in quick from 127.0.0.0/8 to any group 100
block in quick from 0.0.0.0/8 to any group 100
block in quick from 169.254.0.0/16 to any group 100
block in quick from 192.0.2.0/24 to any group 100
block in quick from 204.152.64.0/23 to any group 100
block in quick from 224.0.0.0/3 to any group 100
# Mail.ru bot, EDN Sovintel (Russia)
block in quick from 194.186.55.0/24 to any group 100

..... и далее все, кого мы посылаем. :)

Обратите внимание - группа не привязана ни к какому интерфейсу, это во-первых - мы хотим гнать подобные пакеты прочь на всех активных интерфейсах, а во-вторых, так как машина бастионная, то мы уверены в себе, что от нас не будут уходить спуфинговые пакеты, следовательно, блокировать мы их не стали (что подразумевает и другие меры защиты на хосте, кроме IPF - например, минимизацию, BART итп.).

Теперь пришел черед разрешающих правил для доступа к сервисам:

# Group 200 - Opened incoming ports on bge0
# Group 200 setup
pass in on bge0 head 200
# --------- bge0 interface ---------
# 21 port - FTP service. Disable port and service on Internet servers!
#pass in quick on bge0 proto tcp from any to host_name port=21 flags S keep state group 200
# 22 port - SSH
#pass in quick on bge0 proto tcp from any to host_name port=22 flags S keep state group 200
# 80 port - HTTP
pass in quick on bge0 proto tcp from any to host_name port=80 flags S keep state group 200
# 177 port - x11 service. Disable port and service on Internet servers!
#pass in quick on bge0 proto udp from any to host_name port=177 keep state group 200
# 443 port - HTTPS
pass in quick on bge0 proto tcp from any to host_name port=443 flags S keep state group 200
# 2222 port - SSH Alternative
pass in quick on bge0 proto tcp from any to host_name port=2222 flags S keep state group 200
# 1158 port - OEM console.
# Note: Secure console on Internet servers!
#pass in quick on bge0 proto tcp from any to host_name port=1158 flags S keep state group 200
# Note: OEM console may be on port 5500
pass in quick on bge0 proto tcp from any to host_name port=5500 flags S keep state group 200
# 1521 port - Oracle. Disable port on Internet servers!
#pass in quick on bge0 proto tcp from any to host_name port=1521 flags S keep state group 200
# 7777 port - OHS. Disable port when using WebCache.
#pass in quick on bge0 proto tcp from any to host_name port=7777 flags S keep state group 200
# 8888 port - OC4J main http port.
# Disable port after mount with mod_oc4j using AJP13.
#pass in quick on bge0 proto tcp from any to host_name port=8888 flags S keep state group 200
# 9400 port - WebCache admin default port.
pass in quick on bge0 proto tcp from any to host_name port=9400 flags S keep state group 200
# --------- bge0 interface ---------

# Group 300 - Opened incoming ports on bge1
# Group 300 setup
pass in on bge1 head 300
# --------- bge1 interface ---------
# 80 port - HTTP
pass in quick on bge1 proto tcp from any to host_name2 port=80 flags S keep state group 300
# 443 port - HTTPS
pass in quick on bge1 proto tcp from any to host_name2 port=443 flags S keep state group 300
# --------- bge1 interface ---------

# Group 400 - Opened incoming ports on nge0
# Group 400 setup
pass in on nge0 head 400
# --------- nge0 interface ---------
# 80 port - HTTP
pass in quick on nge0 proto tcp from any to host_name3 port=80 flags S keep state group 400
# 443 port - HTTPS
pass in quick on nge0 proto tcp from any to host_name3 port=443 flags S keep state group 400
# --------- nge0 interface ---------

Важно - мы обязательно группируем эти правила и привязываем к интерфейсам. Важно - мы указываем для протокола TCP пакеты с флагами S (SYN) - инициирование сессии и задаем модификатор keep state (запомнить в таблице состояний).

Так как перед финишем у нас будет группа разрешающих исходящих и возвратных правил, разрешать исходящие пакеты DNS нет никакой необходимости, только для серверов входящие:

# 53 port - DNS.
# --------- bge0 interface ---------
# Allow incoming DNS requests to server (DNS-server)
#pass in quick on bge0 proto tcp/udp from any to host_name port=domain keep state group 200
# --------- bge0 interface ---------
# --------- nge0 interface ---------
pass in quick on nge0 proto tcp/udp from any to host_name3 port=domain keep state group 400
# --------- nge0 interface ---------

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

То же самое относится к NTP:

# 123 port - NTP.
# --------- bge0 interface ---------
# Allow incoming NTP requests to server (NTP-server)
#pass in quick on bge0 proto udp from any to host_name port=ntp keep state group 200
# --------- bge0 interface ---------

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

Собственно, разрешающая группа:

# Group 700 - Outgoing and callbacks sessions
# Group 700 setup
pass out all head 700
# Allow connections originating from local machine out
pass out quick proto tcp all flags S/SA keep state keep frags group 700
# Enable outgoing UDP from server
# Note: We dont open it for security reasons, however
# it must be open when use DNS-servers for zones
# transfers, outgoing traceroute etc.
pass out quick proto udp all keep state group 700
pass out quick proto icmp all keep state keep frags group 700

Здесь мы разрешаем себе все, в чем выше отказали другим ;) - исходящие фрагменты, пакеты SYN-ASK... ;)

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

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

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

# Finally block all unmatched
block in quick all

Несколько пояснений.

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

Отсюда проистекают те сокращения, которые произведены в группах и списках правил в сравнению с опубликованными повсюду примерами.

С другой стороны, я сознательно не утруждаю себя ни созданием honeypots, ни сокрытием того факта, что машина защищена файрволом. Да, приемы сокрытия фактов защиты существуют, например, в посылке пакета RST вызывающему, либо destination/port unreacheable. Но зачем я буду утруждаться посылкой пакета, когда можно и так выяснить, что машина под защитой, а тратить ресурсы (особенно сетевые) на ответы в большинстве случаев совершенно ни к чему.

Также можно заметить, что я чхал на логгирование пакетов. Я использую журналирование только первого пакета и только один раз:

# Block nmap OS fingerprint attempts
block in log first quick proto tcp all flags FUP

Бывает, что мне интересно, кто сканировал мои порты. Но вести гигабайтные логи, просто "шоб було", не заглядывая в них годами, мне как-то претит.

Собственно, вот и все.

Можно взять NMAP и потыкать в защищенную машину с подобающим набором острых опций, дабы убедиться, что все в ажуре.

"А я просто закроюсь яйцами и пускай ломают ноги!" :)

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

воскресенье, 19 апреля 2009 г.

Solaris, multihomed-хосты и IPFilter

Задача конфигурирования для Solaris 10 multihomed-хоста (оконечного сервера, подключенного в две сети) неожиданно оказалась более сложной, чем описывается.

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

В теории все гладко. Гладко настолько, что в мануалах оказалось даже недостойно существенного упоминания**. Я умолчу о том, что в мануалах отсутствуют даже простенькие примеры на указанную тему и интернет практически заполнен воплями о помощи в конфигурировании подобных систем, на которые гуру хранят гордое и пренебрежительное молчание - де, задача тривиальна.
___________________________
** Мне пришлось выслушать мнение нескольких специалистов, заверявших меня, что даже (!) в Windows использование более, чем одного интерфейса приводит якобы к перебоям в функционировании обеих подключений. Что более, чем странно, так как я много лет пользуюсь именно подобным подключением рабочей станции и множества серверов без единой проблемы.

Однако, все не настолько тривиально.

Во-первых, источники в Интернете утверждают взаимоисключающие вещи. Например, чем же разделяются записи в /etc/defaultrouter. Встречались настолько уверенные заявления (Например, что IP-адреса в оном файле разделяются в Solaris 10 пробелами), что пришлось усомниться в собственном опыте и проверить на кошечках. Оказалось, что, хотя в мануалах нигде нет явного примера с несколькими шлюзами, и об этом упоминается более, чем абстрактно - верно первое встреченное в гугле утверждение, и записи в /etc/defaultrouter разделяются символами новой строки. То бишь - каждый шлюз - с новой строки.

Во-вторых, выяснилось, что статические роуты не нужны и команда route должна выводить следующее:

root @ host / # route -p show
No persistent routes are defined

В-третьих, выяснилось, что оконечная машина под Solaris действительно ответные пакеты разбрасывает по всем доступным интерфейсам, и необходимо принимать определенные меры (не обязательно multipathing), чтобы ответные пакеты уходили на тот интерфейс, с которого поступали входящие пакеты. Причем при ответах используется алгоритм round-robin, если в /etc/defaultrouter указано более одного шлюза по умолчанию.

Опуская все страдания и попытки, отмечу, что наиболее простой вариант решения последней задачи действительно оказался с использование IP Filter. Отмечу лишь, что пляски с бубном, роутингом, форвардингом, таблицами маршрутизации и командой route результатов не дали.

Вот фрагмент шаблона конфигурации IP Filter, написанный по следам указанной статьи:

# Group 650 - Ports traffic separation
# Group 650 setup
pass out all head 650
pass out quick on bge0 to nge0:Gateway_Net2_IP from host2 to any group 650
pass out quick on bge0 to nge1:
Gateway_Net2_IP from host3 to any group 650
pass out quick on nge0 to bge0:
Gateway_Net1_IP from host1 to any group 650
pass out quick on nge1 to bge0:
Gateway_Net1_IP from host1 to any group 650
pass out quick on nge0 to nge1:
Gateway_Net2_IP from host3 to any group 650
pass out quick on nge1 to nge0:
Gateway_Net2_IP from host2 to any group 650

Как следует из приведенной конфигурации, ключевым набором правил является группа 650, разделяющая ответный трафик портов по портам происхождения. Данный пример относится к серверу, имеющем три активных интерфейса - bge0, nge0 и nge1, которым назначены адреса и имена хостов host1, host2 и host3 соответственно, при этом host1 находится в одной сети, а host2 и host3 - соответственно во второй, в каждой сети по одному шлюзу.

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

воскресенье, 5 апреля 2009 г.

Поддается ли экономика формализации?

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

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

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

Простая логика приводит лишь к одному-единственному выводу.

Почему 11 сентября пресловутый боинг, вместо того, чтобы лететь, куда все ожидали, прилетел туда, куда прилетел?

Потому что за штурвалом сидел человек, которому было нужно, чтобы он прилетел в здание ВТЦ.

Что бы по этому поводу не думали остальные пассажиры боинга.

"Дорогие мои, штурвал - не у вас. Даже, если мы позволили вам на некоторое время думать, что он у вас - он не у вас. Правила игры определяем мы, законы экономики нам не указ, мы хотим так."

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

У боинга есть пилот, который летит туда, куда хочет. Автопилот может в теории совершать маневры - но жестко ограниченные определенными степенями свободы. Таких маневров он не совершает.

Взялся пилот за штурвал - автопилот выключился.

Откуда все это следует?

Из наблюдения за реакциями черного ящика. Чисто кибернетический эксперимент.

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

За штурвалом сидит пилот, который хочет лететь туда, куда хочет лететь он.

А все остальные - включая нас с вами - могут лишь до последнего гадать, а не в Близнецы ли мы летим.

PS. Нет, наш пилот вовсе не намерен ушатать всех нас до единого. Зачем ему победа без почитателей, налогоплатльщиков, слуг и служанок? Театр будет слишком пуст. Но -

"...Волк и заяц, тигры в клетке -
все они марионетки
в ловких и натруженых руках".