Составление пакетных фильтров


Здесь описывается, как использовать команду ipfw  для создания фильтров различного назначения.

Простые примеры

В качестве первого примера можно рассмотреть фильтр, который запрещает прохождение всех пакетов с некоторого неблагонадёжного адреса 1.1.1.1 на адрес 2.2.2.2:
ipfw addb reject all from 1.1.1.1 to 2.2.2.2
Поскольку враги имеют тенденцию группироваться, можно закрыть прохождение пакетов со всей вражеской сети:
ipfw addb reject all from 1.1.1.0/24 to 2.2.2.2
Число 24 после символа "/" (слэш) означает длину маски в битах. Длина маски 24 как раз соответствует сети класса C, состоящей из 256 узлов.

Используя символ  ":" можно переписать предыдущую команду следующим образом:

ipfw addb reject all from 1.1.1.1:255.255.255.0  to  2.2.2.2
Следующая команда завершает этот абзац:
ipfw addb reject all from 1.1.1.0/24 to 0/0
Она полностью блокирует все пакеты из вражеской сети 1.1.1.0 класса C посланные на любой адрес (если, конечно, они будут проходить через данный маршрутизатор).

Фильтрация по номерам портов

Теперь предположим, что мы хотим написать фильтр, который позволит всем обращаться к сервису  smtp (почтовый агент) на машине с IP адресом  192.5.42.1
Это можно сделать следующей командой:
ipfw addb accept tcp from 0/0 to 192.5.42.1 25
Ключевое слово tcp определяет, что фильтр будет применяться только к TCP пакетам. Сразу за адресом хоста следует номер порта 25, который и определяет сервис  smtp.

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

ipfw addb accept tcp from 0/0 to 1.1.1.1 900:5000 25 113
разрешит прохождение TCP пакетов на адрес 1.1.1.1, если целевой порт при этом попадает в диапазон
от 900 до 5000 или равен 25 (smtp) или 113 (ident).
 

IP spoofing

В предыдущих примерах адрес источника использовался как главный и единственный критерий проверки благонадёжности источника. К сожалению, имеется возможность посылать пакеты с неблагонадёжного адреса подставляя в качестве обратного адреса тот, которому вы доверяете (этот вид атаки называется IP spoofing). Понятно, что проверять один адрес источника недостаточно. Необходимо также проверить каким путём шёл пакет или, что более практично, через какой интерфейс он был принят.

Пример сети показан ниже:
 
 







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

ipfw addb rf0 reject all from innerhost/16 to 0/0
В отличие от предыдущих примеров, этот фильтр будет применяться только к пакетам приходящим через интерфейс rf0. Пакеты, поступающие через любой другой интерфейс, блокироваться не будут.
(в примере предполагалось, что внутренняя сеть имеет адреса сети класса B)
В качестве дополнительной меры, возможно, имеет смысл заблокировать также прохождение пакетов с адресом источника из сети loopback (127.0.0.0):
ipfw addb rf0 reject all from 127.0.0.0/8 to 0/0
IP spoofing как метод атаки широко использовался в сети Интернет (для дальнейшей информации смотри CERT summary CS-95:01 , а также summaries на сервере  CERT WWW site ).

Важно понимать, что злоумышленник может использовать метод  IP spoofing для взлома вашей системы даже несмотря на то, что обратные пакеты никогда не вернутся к отправителю. Смотри, например CERT advisory CA-95:01 .

Фильтрация TCP соединений

TCP/IP клиенты обычно используют порты в диапазоне от 900 до 5000, а сервера обычно обслуживают порты с номерами ниже 900 или выше 5000. Следовательно, следующая пара фильтров позволит запретить любым внешним клиентам работу с нашими серверами (предполагается, что rf0 это интерфейс соединяющий нас с внешним миром):
ipfw addb rf0 accept tcp from 0/0 to 0/0 900:5000
ipfw addb rf0 reject tcp from 0/0 to 0/0
Первый фильтр пропускает все входящие извне пакеты, посылаемые на сервисы с портами в диапазоне от 900 до 5000 (обычно используемые нашими клиентами), а второй фильтр отбрасывает всё остальное.

К сожалению, этого недостаточно. Некоторые внутренние сервера могут использовать порты в диапазоне от 900 до 5000. Предыдущая пара фильтров позволит внешним станциям работать с нашими серверами. Проблема в том, как закрыть внутренние сервера использующие диапазон портов от 900 до 5000 и в то же время позволить работать нашим клиентам в этом же диапазоне. Одно из решений - блокировать попытки установления соединения между внешним клиентом и внутренним сервером.
Модификатор tcp_connection даёт такую возможность:

ipfw addb rf0 reject tcp connection from 0/0 to 0/0 900:5000
ipfw addb rf0 accept tcp from 0/0 to 0/0 900:5000
ipfw addb rf0 reject tcp from 0/0 to 0/0
Первый фильтр предотвращает попытки установить соединение извне с нашими внутренними серверами в диапазоне портов от 900 до 5000. Второй фильтр разрешает другие входящие TCP пакеты в этом диапазоне, и последний фильтр отбрасывает все прочие TCP пакеты.

Ненадёжный UDP

В отличие от протокола TCP , который ориентирован на установление соединений, UDP протокол использует отдельные пакеты (датаграммы). В этом протоколе, каждый пакет передаётся независимо от других и логические сеансы, которые могли бы устанавливаться между UDP/IP клиентом и сервером существует только на уровне приложений и не видны на уровне UDP.

Поскольку все пакеты независимы, по заголовку пакета невозможно определить, посылается пакет от сервера клиенту или наоборот (фактически, в протоколе UDP , участники действуют как равноправные партнёры и термины сервер и клиент явно не определены.
Поэтому лучшее, что мы можем сделать, это возможно более точно определить диапазон портов UDP, который может использоваться для связи с внешним миром. да-да-да легко сказать...

Сервер имён (DNS) является примером сервера, использующего протокол UDP.
Предполагая, что rf0 - это наше соединение с внешним миром, следующая пара фильтров обеспечит взаимодействие между нашим и внешними DNS серверами, заблокировав весь остальной UDP трафик:

ipfw addb accept udp from 0/0 53 to 0/0 53
ipfw addb rf0 reject udp from 0/0 to 0/0
Хотя это может показаться простым, на самом деле очень трудно реализовать более открытую политику в области UDP обмена, не создав при этом больших дыр в безопасности. Если вы решите разрешить локальным клиентам общаться с внешними UDP серверами, то примите во внимание следующие соображения (это ДАЛЕКО не полный перечень):
  1. Если вы имеете NFS сервера, имейте в виду, что традиционно они используют UDP порт 2049 (TCP/IP реализации NFS используют TCP порт 2049, который, вероятно, может быть защищён с помощью модификатора tcp_connection  - смотри выше).
  2. Некоторые реализации RPC portmapper имеют серьёзные проблемы с безопасностью. Будьте очень осторожны, разрешая внешний доступ к внутреннему ресурсу portmapper (TCP и UDP порт 111).
  3. Будьте очень осторожны в выборе того, какие порты источника и назначения вы разрешаете. Вы можете поддаться искушению разрешить приём входящих пакетов, которые приходят с определённых  UDP портов. Если вы сделаете это, не забудьте, что злоумышленник может легко посылать любые  TCP/IP и UDP/IP пакеты с любыми номерами портов и комбинациями адресов.
  4. Некоторые сервисы сети Microsoft LAN manager используют UDP. Зная патологическую неприязнь фирмы Microsoft к открытым и безопасным протоколам и учитывая беспрецедентное число ошибок в реализации, лучше исключить всякую возможность потенциальным злоумышленникам воспользоваться этой дырой в безопасности:

  5. ipfirewall addb rf0 reject tcp from 0/0 to 0/0 135:139
    ipfirewall addb rf0 reject udp from 0/0 to 0/0 135:139
    Данный фрагмент достаточно надёжно закрывает внутреннюю сеть от большинства возможных посягательств несанкционированного доступа к вашей сети (если в ней имеются серверы или станции на базе Windows NT/95/98).

IP фрагменты

Модификаторы  ip_fragment, ip_head_fragment и ip_tail_fragment предназначены для управления потоком фрагментированных IP пакетов. Чтобы понять, как использовать их в своих фильтрах, вы должны обратить внимание на следующие моменты:
  1. Фильтр, который проверяет номера портов TCP или UDP, никогда не проверяет  IP фрагменты, если только это не первый фрагмент в последовательности.
  2. если ваш фильтр позволяет приём IP фрагментов, то злоумышленник может применить атаку типа "denial-of-service" (отказ в обслуживании), посылая огромное число фрагментов с разными адресами источника, что может привести к нехватке памяти на вашем маршрутизаторе.
Если вы хотите предотвратить потенциальную атаку типа denial-of-service, то, вероятно, единственное решение заключается в запрете на приём всех фрагментированных пакетов:
ipfw addb reject all ip_fragment from 0/0 to 0/0
Это, безусловно, повышает общий уровень защищённости, хотя следует иметь в виду, что злоумышленник может использовать другие пути для атаки (например, просто забрасывая вас пакетами или просто посылая кучу бесполезной почты:)

Кроме того, блокирование всех фрагментированных пакетов может помешать нормальной работе.
К примеру, в каждом сегменте сети есть понятие максимально возможного размера пакета (обычно около 1500 байт). Но даже если отправитель посылает не фрагментированный пакет, нет никакой гарантии, что он дойдёт таковым до получателя. Вполне вероятно, что где-то по пути встретится участок с меньшей максимально допустимой длиной  пакета, и он будет разбит на фрагменты. Даже новейшие протоколы определения минимальной длины пакета на всём пути от источника до получателя не гарантируют успеха, поскольку каждый IP-пакет доставляется независимо от других и может идти совершенно различными путями. То есть, блокирование фрагментированных пакетов может приводить к нарушениям в работе сетевых приложений (временным, либо постоянным) с определёнными хостами.

Если вы решите разрешить прохождение фрагментированных пакетов, то, вероятно, одним из первых фильтров можно смело поставить:

ipfw addb accept all ip_tail_fragment from 0/0 to 0/0
Разрешение прохождения фрагментов пакета кроме первого не создаёт проблем с безопасностью (за исключением случаев атаки "отказ в обслуживании") поскольку первый фрагмент пакета, который несёт основную информацию о его назначении, будет контролироваться другими фильтрами. Если первый фрагмент пакета будет отвергнут каким-либо фильтром, то оставшиеся фрагменты будут доставлены получателю и уничтожены его программным обеспечением по истечении некоторого интервала времени (обычно 60 секунд).
 

Регистрация пакетов

ipfirewall регистрирует все отвергаемые пакеты соответствующим сообщением в системном журнале. Дополнительно можно включить регистрацию принимаемых пакетов, указав ключевое слово log.
Например, команда:
ipfw addb accept log icmp from 0/0 to 0/0
будет регистрировать все принимаемые ICMP пакеты.

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


Главная страница