В Интернете есть много пространных рассказов про то как настроить межсетевые фильтры, экраны, объединить сети и прочие сложности. Я про это писать не буду. Я напишу несколько простых рецептов и примеров, вполне готовых к использованию и рассчитанных на рядового пользователя, которые помогут ему защититься от внешнего вторжения.
Кроме того, здесь я расскажу об одной полезной для web-разработчика (и не только) дополнительной возможности FireWall.
Лично мне понадобился FireWall только когда я стал работать в большой компании в тесном сотрудничестве со многими людьми и мне пришлось открыть ssh-доступ, http-доступ на мою рабочую машину. Кроме того, моя собственная работа привела к тому, что мне пришлось открыть десятки портов, а слушали эти порты приложения, находящиеся в процессе разработки… Одним словом, мне понадобился FireWall, но я не уверен, что он жизненно необходим вам.
Что такое FireWall (коротко)
FireWall — это модуль ядра, который обрабатывает всю входящую информацию до того, как она будет передана соответствующим программам; и всю исходящую информацию, какой бы программой она ни была отправлена. FireWall анализирует эти данные и либо пропускает их дальше, либо блокирует, основываясь на некоторых правилах. Правильная настройка FireWall позволяет защитить систему от нежелательных внешних вторжений и ограничить возможности программ, работающих внутри системы.
Это всё теория. Главное для нас то, что FireWall — это не программа, а подсистема ядра, что он может блокировать трафик и что его можно гибко настраивать.
Подготовка
Прежде всего, вам надо загрузить модуль FireWall в ядро.
Для тестирования, вы можете сделать это «руками» командой:
ВНИМАНИЕ! После того, как вы загрузите FireWall вступят в действие настройки по умолчанию и вы будете полностью изолированны от внешнего мира! Поэтому не торопитесь с выполнением этой команды, не прочитав, как настраивать FireWall, или не сохранив инструкции на своём локальном диске.
Чтобы модуль загружался сам при каждой загрузке системы, добавьте строчку:
в файл /boot/loader.conf.
Строго говоря, /boot/loader.conf можно и не трогать, модуль подгрузится и если в /etc/rc.conf присутствует firewall_enable=»YES» (см. ниже).
Написание правил
Я не буду здесь пересказывать man 8 ipfw. Он есть в каждой системе, а в сети он есть (хотя и немного устаревший) переведённый на русский язык. Я приведу готовые примеры.
Пример 1: Можно всё
Чтобы разрешить весь трафик, достаточно одного правила
00100 pass all from any to any
Смысл этого правила понятен и без чтения документации: «Пропускай все пакеты от кого угодно к кому угодно». Это правило пригодится вам во время отладки. Неминуемо у вас будут получаться конфигурации в которых вы будете полностью отрезаны от мира. Это правило — идеальное временное решение.
Первое число это номер правила. Каждое правило пронумеровано и проверяются они в порядке возрастания номеров.
Пример 2: Паранойя
Эти правила разрешают только соединения инициированные вами. Снаружи никто даже не может попытаться подключиться. Ваша машина даже не будет «пинговаться», то есть большинство окружающих будут уверены, что она вообще выключена.
Для пользователя эти правила тоже очень жёсткие, они позволяют ему пользоваться далеко не всеми ресурсами сети.
Давайте рассмотрим эти правила по порядку.
00100 allow all from any to any via lo0
00101 deny all from any to 127.0.0.0/8
00102 deny all from 127.0.0.0/8 to any
00500 check-state
00501 deny all from any to any frag
00502 deny tcp from any to any established
00600 allow tcp from any to any 80 out via bge0 setup keep-state
00601 allow tcp from any to any 110 out via bge0 setup keep-state
00602 allow tcp from any to any 143 out via bge0 setup keep-state
00603 allow tcp from any to any 25 out via bge0 setup keep-state
00700 allow tcp from any to XX.XX.XX.XX 53 out via bge0 setup keep-state
00701 allow udp from any to XX.XX.XX.XX 53 out via bge0 keep-state
00702 allow tcp from any to YY.YY.YY.YY 53 out via bge0 setup keep-state
00703 allow udp from any to YY.YY.YY.YY 53 out via bge0 keep-state
Правила 100-102 разрешают общение вашего компьютера с самим собой. Может оказаться, что вам эти правила не нужны, но без них могут не заработать некоторые программы.
Правило 500 проверяет виртуальные правила (о них чуть ниже). Если виртуальные правила не сработали, то поиск подходящего правила продолжается.
Правила 501 и 502 запрещают все соединения, которые уже созданы.
Правила 600-603 создают виртуальные правила (keep-state), пропускающие (allow) пакеты для соединений, которые инициированы (setup) вами (out via bge0).
Кстати, имя интерфейса bge0 вам следует изменить на имя вашего интерфейса.
Причём правила 600-603 позволяют вам работать только с WWW (порт 80) и e-mail (порты 25, 110, 143). Если вам нужно работать и по другим протоколам, то добавьте правил по аналогии.
Правила 700-703 аналогичны предыдущим, они позволяют вам работать с DNS, причём только с легальными DNS вашего провайдера. Замените XX.XX.XX.XX и YY.YY.YY.YY на адреса ваших DNS. Добавьте или удалите правила по необходимости.
Пакеты, которые не удовлетворяют ни одному правилу, будут блокированы FireWall.
Таким образом мы получили набор правил, который не пропускает входящие пакеты кроме тех, которые пришли в ответ на ваш запрос. Кроме того, вы можете работать только с ограниченным кругом Интернет-сервисов. То есть если у вас заведётся какая-то программа (разве такое возможно под FreeBSD?!), желающая «выйти в интернет» у неё это скорее всего не получится. Кроме того, вы не сможете воспользоваться никакими DNS, кроме тех, которым доверяете. Это сразу резко сужает круг возможных атак.
Пример 3: Разумный компромисс
Параноидальная конфигурация хороша, но уж очень параноидальна. Сам я пользуюсь более либеральными настройками:
00100 pass all from any to any via lo0
00101 deny all from any to 127.0.0.0/8
00102 deny all from 127.0.0.0/8 to any
00500 check-state
00502 deny all from any to any frag
00501 deny tcp from any to any established
00600 allow tcp from any to any out via bge0 setup keep-state
00601 allow udp from any to any out via bge0 keep-state
# allow in to 80
00700 allow tcp from any to any 80 in via bge0 setup keep-state
# ping
02000 allow icmp from any to any out icmptype 8
02001 allow icmp from any to any in icmptype 0
Здесь разрешён весь трафик инициированный мной (на любые порты).
Правило 700 разрешает всем обращаться к Web-серверу, размещённому на моей машине. Вы можете добавить аналогичные правила для других сервисов. На пример:
00701 allow tcp from AA.AA.AA.AA to any 22 in via bge0 setup keep-state
Это правило разрешит обращаться к вашему sshd с машины с IP-адресом AA.AA.AA.AA.
Наконец, правила 2000 и 2001 разрешают вам «пинговать» других. Вас по-прежнему никто «пинговать» не сможет.
Чтобы ping на вас работал, поправьте эти правила вот так:
02000 allow icmp from any to any icmptype 8
02001 allow icmp from any to any icmptype 0
Или напишите просто:
02000 allow icmp from any to any
Это не опасно.
Строго говоря, грамотный хакер сможет много узнать о вашей системе даже с помощью ping, но в большинстве случаев это все же не опасно.
Загрузка правил
Итак, вы выбрали правило, поправили его под свои конкретные нужды и хотите его загрузить. Для загрузки правил есть программа, которая называется так же, как и модель ядра — ipfw. Существует два способа загрузки.
Первый способ — загрузить правила из файла:
ipfw /полный/путь/к/файлу
Перед загрузкой не забудьте удалить существующие правила:
Второй способ более громоздок, но он более общепринятый. Для загрузки пишется скрипт, который загружает правила по одному. Традиционно, скрипт имеет примерно такую организацию:
#!/bin/sh
ipfw -q -f flush # чистим
# устанавливаем переменные
oif="bge0" # мой интерфейс
cmd="ipfw -q add " # для краткости
ks="keep-state" # для краткости
# теперь загружаем, используя краткие "макросы"
$cmd 00500 check-state
$cmd 00502 deny all from any to any frag
$cmd 00501 deny tcp from any to any established
$cmd 00600 allow tcp from any to any out via $oif setup $ks
$cmd 00601 allow udp from any to any out via $oif $ks
Чтобы при старте системы всё загружалось автоматически, вам надо дописать в файл /etc/rc.conf строчки:
firewall_enable="YES"
firewall_script="/etc/rc.ipfw"
Упомянутый здесь файл /etc/rc.ipfw может называться и по другому (это имя выбрал я сам). Это просто файл-скрипт, загружающий правила.
Диагностика
Для диагностики есть две команды:
показывает все правила, а
показывает правила и счётчики пакетов, которые совпали с этими правилами. (Имеются полезные дополнительные ключи. Подробнее смотрите документацию.)
Не удивляйтесь, в списках правил всегда будет присутствовать правило, которое вы явно не загружали:
65535 deny ip from any to any
Это правило по умолчанию, оно присутствует всегда и удалить его нельзя. Оно обрабатывается последним в цепочке правил и останавливает все пакеты, которые не совпали ни с одним правилом.
Ограничение трафика
Наконец, ipfw предоставляет возможность, которая никак не связана с безопасностью, но может быть очень полезной при отладке web-приложений. Ipfw может эмитировать торможение сети.
Не вдаваясь в детали (которые всегда можно прочитать в man), приведу сразу пример правил. Загрузить их можно вот такими тремя командами:
ipfw pipe 1 config bw 50Kbit/s queue 20
ipfw queue 1 config pipe 1 weight 50 queue 20
ipfw 00099 add queue 1 tcp from any 9090 to any
Первой командой мы создали трубу (pipe) с скоростью пропускания 50Kbit/s и длиной очереди 20 пакетов. Второй командой мы создали очередь (queue), которая работает с нашей трубой. И третьей командой мы создали правило, которое отправляет в нашу очередь все пакеты, которые идут с порта 9090. То есть даже если вы будете соединяться сами с собой через порт 9090, то ширина канала будет ограничена 50Kbit/s.
Этот механизм позволяет не только ограничивать ширину, но и эмитировать потери пакетов и задержки. Подробнее читайте документацию на ipfw, там всё написано.
Я лишь добавлю, что очерёдность выполнения этих трёх команд не важна. А чтобы удалить трубы и очереди, есть две специальные команды:
ipfw -f pipe flush
ipfw -f queue flush
Не забывайте удалять текущие настройки перед загрузкой новых.